0:00
Welcome to this course on mastering technical interviews for software
0:05
engineering roles. These interviews often hinge on your ability to
0:10
confidently solve problems using data structures and algorithms which can feel
0:15
challenging without the right foundation. In this comprehensive course, Parth from Destination Fang will
0:22
strip away the intimidation and equip you with the essential knowledge starting with the core concepts of data
0:29
structure, algorithm, and fundamental analysis like time and space complexity.
0:35
You'll learn how to judge an algorithm's efficiency using big O notation and apply this important skill to code
0:42
blocks. The course covers almost every major data structure and algorithm pattern from arrays, linked lists,
0:49
stacks, and cues to advanced topics like trees, graphs, dynamic programming, and
0:55
backtracking. So, good luck learning. Hello friends, hope you're having a fantastic day today. This is going to be
1:01
50hour long course that contains everything there is to know about technical interviews, data structures,
1:07
and algorithms. There are about 20 concepts that I have created that comprise the entirety of technical
1:14
interviews and that contains different data structures, different algorithms and different coding patterns. We are
1:19
going to cover each and everyone in very much detail. We will understand the concept for them and then we would solve
1:26
lots and lots of interview problems associated with that. By the end of this course, you would have solved close to
1:32
200 most task, most liked and most popular interview problems and you would be able to solve majority of technical
1:39
interview problems out there and then it's just a matter of sheer practice that you will have to do on your part. I
1:45
can guarantee you that this is going to be a very high quality in-depth course where it is completely beginnerfriendly
1:51
and we will go deeper and deeper into the most advanced topics and I will try to explain it in as much detail as I can
1:59
so you can be absolutely prepared for anything to come in your technical interviews. Now a quick introduction
2:05
about myself. My name is Parvas and I have bachelor's and masters in computer science. I have been in the IT industry
2:10
for close to 10 years now and I have worked at companies like Microsoft, RBC, Nokia and currently working as a
2:16
solutions architect for Cinniplex. I have joined my career as a junior developer and have gone through multiple
2:22
transitions. I have been absolutely blessed by lot of important mentors who have guided me correctly in my career
2:28
and this is something me giving back to the community. Now I also run my own YouTube channel named Destination Fang
2:35
and I would highly encourage you if you can go and support me on that channel as well. I teach about how you can go ahead
2:41
in your career and how you can ace your technical interviews, behavioral interviews and system design interviews
2:46
and your support matters a lot for me. So it can motivate me to keep making more videos like this. On top of it, you
2:52
can stay up to date on the latest and greatest things that I'm currently working on. Few fun facts about me. I love going on hikes. I love watching
2:59
movies and I love playing with my twin daughters. I am based in Canada and this
3:04
is a beautiful country. So if you get a chance to visit, please come and see it anytime. Now I would not deviate from
3:10
the main topic that why we are here. So without any delay, let's get started. Now what is DSA? DSA stands for data
3:16
structure and algorithm. Now everything in computers is made out of data. These are the bits and pieces of zeros and
3:23
ones that hold all the information. It can be a text or a book or a PDF or the
3:28
video you are watching. Anything can be represented as data. And the way we store and organize the data is referred
3:34
to as data structures. Now there are many different ways of storing data. You can store them in a straight fixed uh
3:41
given format that can be defined as array. You can have one bit of data live over here, next live over here and after
3:47
one the next lives over here. But this guy does not know where this guy exist. And that's an example of link disc. And
3:53
there are bunch of other way different ways to understanding different data structures. Now there are linear data
3:59
structures, nonlinear data structure, hierarchical data structures, hashbased data structures and they all have
4:04
different purposes which we will learn more in the classification of data structures. Now let's understand that
4:09
what is algorithm? Algorithm is nothing but following step by step to complete
4:15
certain procedure and achieve an expected outcome. Now this can be anything. If we strictly talk about from
4:23
the perspective of computer science, there are algorithms that do certain things really well like sorting items,
4:29
searching any particular item in the existing given data structure, um recursion, dynamic programming, greedy
4:36
approach, divide and conquer. And these are all the strategies that we typically use in our day-to-day operations as
4:42
well. We just don't realize that these are algorithms. And then there is the combination of data structure algorithms
4:49
that help us solve many complicated problems. So that's why the companies
4:54
that are substantially large in the IT industry, these are the fang companies or top tier IT companies. They usually
5:02
build products that scale up to millions and billions of users. And they want to
5:07
have the most efficient, most optimal approach to any given problem. And
5:12
that's why they love asking these questions to understand the technical progress and proficiency of any
5:19
candidate and that's where you need to be learning about these things. Now how
5:24
does a solution can be defined as optimal? Well, there are two things that defines that and that is called space
5:30
complexity and time complexity and they are usually referred by big O notation.
5:35
Now we will understand the full theory on that in one of the sections. But how does companies typically evaluate your
5:42
solution? They are looking for number one whether you can reach to the optimal solution or not. That's a basic
5:48
criteria. But that is not just the only criteria. Now in a typical interview
5:53
process you are expected to go through somewhere between 3 to five rounds of technical interviews each lasting about
5:58
45 minutes to 1 hour. And for each of the interview you are expected to solve anywhere between two to three medium to
6:05
hard DSA problems. Now you are being judged based on your thinking abilities,
6:10
your communication, whether you are a good person to work with. Can you think of different scenarios, different edge
6:17
cases? Are you able to come up with the optimal solution? What does your approach looks like? If you have a
6:22
suboptimal solution, can you reach to that optimal solution? Can you ask for proper hints? Can you convince your
6:28
recruiter or interviewer about your solution? Can you walk through it? Can you code it out? And you know the
6:34
complicated part is they typically don't give you a full IDE or editor. They
6:40
typically ask you to solve this problem on a whiteboard if it's in person or on
6:45
a Google doc if that's going to be a virtual interview. So that's why there are a combination of skills that you
6:52
will have to accumulate throughout this course and your preparation journey to be able to clear multiple different
6:58
technical interviews and we will learn that in the next section. Now how do we
7:03
even judge an algorithm? Well, there are three things that we are looking for. First one is the accuracy of algorithm.
7:09
That is quite straightforward that if I expect my algorithm to generate pizza or find the shortest number out of all of
7:16
these given numbers. If it is exactly doing that which means my algorithm is accurate and it needs to do that for all
7:23
the different edge cases and all the different scenarios. Second thing is time complexity and third thing is space
7:29
complexity. So first let's understand that what is time complexity through an
7:34
example by these deck of cards. Time complexity is nothing but how much
7:40
longer will it take for you to complete your algorithm or your task if the
7:45
number of inputs keeps on growing larger and larger and larger. Let's try to understand that currently I have these
7:52
deck of cards and they are currently just randomized. If I lay them flat on a table and let's say that for simplicity
7:58
I'm trying to figure out that where does heart of six lies amongst these cards.
8:03
Now I don't know but I can keep on opening all the different cards randomly until eventually I found out to a card
8:11
that is heart of six. And notice that I found heart of six right here. But how
8:17
many cards did it took me to find this value? It's just like finding a needle in a haststack. You need to go go one by
8:23
one. And if I had like million cards and all different unique entries, it might
8:28
take me like million attempts before I reach to the card that I'm particularly looking forward. So in this case, we can
8:34
notice that the time it takes for me to complete the expected task increases
8:40
linearly with the increase in the number of inputs. So we can call this time complexity of big O of N. Now big O is
8:48
the definition or a way we write the time complexity and space complexity and
8:54
we are going to talk all about that in a separate topic. But now let's just say focus towards this. Now let's see that
9:00
how does time complexity change based off of how we have our data being
9:05
scattered or how we change our algorithm. Let's take an example. Now in this case we are going to sort all of
9:11
these cards in ascending order and then we are going to lay flat lay them flat
9:16
once again on our card. So this is going to be the smallest value and then we are going to keep on adding all of these
9:23
values on this um table. Now notice that in this scenario once again we are
9:29
trying to find that where does heart of seven is present in this deck of cards. Now I don't know I can't see them but I
9:36
know for a fact that this one is the smallest value. This one is the largest value and if heart of seven is present.
9:42
Let me just open the middle value. So middle value is heart of six. So I know for a fact that all of these cards are
9:49
definitely going to be smaller than six because it's already sorted. So I don't even need to look at these cards. I can
9:56
ignore all these four cards and then I only worry about these three cards. Once again I'm going to open the middle card
10:02
and this one is heart of eight. Now I know because this is sorted so these two values are always going to be greater
10:09
than heart of seven. So this card has to be heart of seven the lucky card and
10:15
that is what we currently have on our table. Now notice that once again we had again eight or nine cards but we only
10:22
needed to open three cards in order to find the card that we were looking for. This one is an example of logarithmic n
10:30
time complexity. Why it's logarithmic n? Because with every single task or every
10:36
single step we make, we are essentially eliminating 50% of all the inputs in one
10:42
go. So here we eliminated four cards. Then for from the remaining three, we eliminated two more cards. If we had
10:48
million cards in just one opening of a card, we would have eliminated 500,000 cards. In the second opening, we would
10:55
have eliminated remaining 250,000 cards. So even if we have like 10 million
11:00
cards, we can very quickly find the value that we are looking for and that is an example of big go of log n time
11:06
complexity. Now let's talk about some other time complexities and other examples. Now the most basic time
11:12
complexity is a constant time complexity. Constant time complexity means that if it takes us let's say 1
11:18
second to do one job for 10 inputs, it will once again take us like 1 second
11:24
even if we had 100,000 inputs. What's an example of that? Let's presume that we currently have this ice tray where we
11:31
have bunch of different black chickpea beans associated with that and they are currently placed in a sorted array in a
11:38
sorted bucket and for each number uh it corresponds to total number of chickpeas
11:44
being present. So like like this one is first one so it only has one chickpea. This one is second one it has two
11:50
chickpeas. Now in this case if I have to figure out that show me five chickpeas
11:55
let's say that that is what I want from my algorithm I can very quickly say that this fifth number is going to contain
12:01
five chickpeas. So I can quickly uh take it take them out and then start counting
12:06
that there are going to be five chick chick chickpeas in my hand. Now even if I had million of these and presumably I
12:12
have like hands longer that can reach up to all of these million associates. I can very quickly find any number of
12:19
chickpeas I want from this given example. So this would be a scenario where the time complexity is going to
12:24
remain constant. Next one is logarithmic time complexity that we already saw an example using the sorted cards. And next
12:31
we also saw an example of bigo of n time complexity where the time increases
12:37
linearly with the given input size. Now let's talk about bigo of n² time complexity. Now for this n square time
12:44
complexity let's presume that we currently have these two deck present. What we are going to do is we are going
12:49
to find a card from this deck and this corresponds to let's say number eight. Now we are going to keep on scanning
12:55
this deck until we find number eight. So we found number eight. That's great. Once again we are going to repeat the
13:01
same process. And this is going to be three. So this one is three. Once again we found the match. Now this one is a
13:07
joker. So let's just ignore that. This one this one is seven. So now for the seven, we will try to keep on shuffling
13:13
through the deck until we find the appropriate seven. And in this case, it took me it took us slightly longer, but
13:19
we eventually find find it. It's basically a matching between two separate decks. Now notice what is going
13:25
to happen for every single card that is currently present in this deck. Worst case scenario, it could be possible that
13:32
we might have to scan this entire deck before we can reach to that end conclusion. So for each of these n
13:38
values we will have to do n work. It's loop within a loop in order to find the
13:44
established goal. And that is an example of bigo of n square time complexity. Now for n cube time complexity basically we
13:51
are just going to have three set of decks where we will take value from one deck. Then we will try to find a
13:56
matching pair from the second deck. Maybe it it could take us as long as it takes and then we will try to find
14:02
another matching from the third deck. So this can take substantially longer but overall this is what n cube time
14:09
complexity means. It's once again loop within a loop within a loop. Now let's talk about some really large time
14:16
complexities. So first one comes to mind is 2 to the power n time complexity. 2
14:21
to the power n complexity means that if you have an input that increases the
14:26
time it takes for you to generate the output multiplies by two every single time. And what is an example of that?
14:34
Let's say that we currently have a coin. Now this particular coin only has two possibility. If I flip it, it can either
14:41
be heads or it can be tails. That's it. But the thing is what if I add one more
14:46
coin into the mix. Now the number of possibility are multiplied by two again because we can have two heads. We can
14:52
have one head and one tail. We can have one head and another tail or we could have two tails. So in this case we have
14:59
four comp four possibilities. If we add one more coin, the possibility once again multiplies by two. We could have
15:06
eight eight possibilities. If we have one more coin, it once again multiplies by two. We could have 16 combinations of
15:13
heads and tails. If I add one more coin, the possibility multiplies by two again. So, we could have 32 combinations. So,
15:19
notice that when we started merely with just two possibilities of flipping a coin, it has very quickly grown to 32
15:27
possibilities just with the addition of four input values. If I keep on adding the input values like 10, it's going to
15:34
be 1,024 and so on and so forth. So it's going to become very large very quickly
15:39
and these are the time complexities that are that we are typically trying to avoid or it becomes very tricky to work
15:46
with them. So do you think that this would be the worst time complexity? Well, you might be mistaken. There is
15:53
also some more time complexities that are more complex than this and that could be in the factorial time. So what
16:00
does factorial time? Let's try to understand it with a simple example. Let's say that we currently have these
16:06
three cards. Treat it as like three seats in a bus or an aeroplane or or a
16:12
movie theater. And then we have three friends who are currently trying to have a seat on these three different places.
16:19
What are the different combinations we can have them seat in these places?
16:24
Well, in the first seat, potentially all three can sit. That's very fair. Now,
16:30
amongst all three can sit, if one sits, then for the second seat, the number of possibilities are two. And for the third
16:37
seat, the number of possibility is one. So, if we have to quantify that what are all the different permutations and
16:43
combinations, there are three possibilities that can have a seat on the first position. There are two
16:49
possibilities on the second position and there is one possibility on the last position and it's a multiplication of them because it's permutations and
16:56
combinations of all the different people trying to have a seat on the first on the second and on the third. So it's
17:01
going to be 3 multiplied by two multiplied by one. So in total we can have six possibilities. If I add one
17:07
more card into the mix and if I add one more person now the whole dynamics change because on the first position
17:14
potentially all four people can sit on the second position potentially three remaining people can sit two and then
17:20
one. If we do the multiplication it comes up to 24. If I have one more card
17:26
and once again if I am trying to have one more person have a seat over here. Now it becomes even more complicated
17:32
because on the first position any of these five people can sit. So it's five possibilities then four then three then
17:39
two and then one. So it's a multiplication of all of these and this comes up to 120. If I add six value it's
17:46
720. So notice that how quickly the number grew from just having six for the
17:53
three time complexity to having 120 possibilities for the remaining two. So
17:58
this is how exponentially the time complexity grows for a problem that
18:03
involves factorial time complexities. Now there are some real cases where we actually do deal in factorial time cases
18:10
and we try to improve upon them using dynamic programming and we are going to see lot of examples of that. Now let's
18:16
try to understand that why do we use the terminology big O to define time
18:21
complexity or space complexity. Uh whenever we are defining the speed of an
18:27
algorithm we would say that it runs in order of the growth rate based off of
18:33
given input size. What I'm trying to say is that if my current input is 10, it runs in let's say 10 seconds. And if my
18:41
given input turns to 1,000, it runs into 1,000 seconds. So we can say that there
18:46
is a linear connection between the input size and the time it takes to execute
18:51
the algorithm. So we can say that this algorithm runs in the order of end time.
18:57
So that's why the O in the big O refers to as the order of whatever the
19:03
component it is that defines the growth rate. So we are trying to calculate the upper bound of growth rate for the given
19:11
algorithm. And that's why we use the terminology big order of whatever the
19:17
input size it relates to. Now I know that you must be getting confused that about all of these different
19:22
terminologies and big go of n and big go of 2 to the power n and n square and whatn not. So let's try to see very
19:29
small brief code blocks that I'm going to explain one by one and then we will
19:34
try to see that why we call it as whatever time complexity it is made off
19:39
of and uh that way it will clear some concepts for you at least at the basic
19:45
level and don't worry if you don't understand some terminology you it would be covered throughout this course so
19:52
just stay stay with me so now we are going to be seeing bunch of examples of different big O So we will see different
19:58
code blocks like this and we'll try to figure out that what is going to be the big O for this particular code block and
20:04
why that is the case. In the very end we are going to see that for each of different time complexities what does
20:10
the impact or the growth rate is for that particular type of time complexity. So that would really put the things into
20:17
the perspective that why these numbers matter so much. So let's try to understand this very simple code block.
20:23
Basically we have a very simple method that that is called get first element that takes in an array as an input and
20:31
it just simply returns the very first element present inside the array. Now we
20:36
know that if we are given an array like this it's only going to take like x amount of constant amount of work in
20:44
order to fetch the values. Even if it's an array of size five or of an area of
20:49
size 5,000 or 5 million, it's always going to remain the same amount of time it takes to run this code. So we can
20:56
call this as big O of one or constant time complexity for this code block. So
21:02
this is a very simple example of that. Now let's try to understand more nuanced example. So in this this case we are
21:09
basically doing a binary search. Now if you are not familiar with this term, don't worry about it. This is basically
21:15
the same stuff we did with the sorted cards we had where we were finding the middle card and then based off of that
21:22
we were either eliminating like one side of the cards or we are eliminating the other side of the cards and then we were
21:28
doing some other work. This is exactly the same stuff. Uh the idea is that we
21:33
simply go in we fetch a mid value and for that mid value we check that if the given target value if that is equal to
21:40
mid we return it. If that is not equal to it, we either check the left side of the array or right side of the array and
21:46
then we simply return the answer. So basically we are running this code in big go of logarithmic time log end time
21:52
and that is what this is this is an example of. Same way for this particular codebase uh if you check we are doing a
22:00
linear search. Basically we are given an array so that contains bunch of different values present within an array
22:07
and a target value we are trying to find from this given value. Now we don't know target can be at this location, this
22:13
location or at the very last location and in the worst case scenario we might have to iterate over the entire array
22:19
before we find the appropriate value. That is what we are doing. So we are running a loop through this given array
22:25
and then we are trying to find the appropriate value and then we can return its position basically. So in this case
22:32
we can say that this is going to run in big go of end time or a linear time
22:37
because basically if we have 1 million input then it might take us like 1
22:43
million more times compared to if we only had just one input or two inputs.
22:48
Now let's try to see this example. This is basically a very popular algorithm
22:53
that we will be using quite a lot in lot of the lead code problems. All it is
22:58
doing is basically it's merge sort. So if basic the idea is that we are given
23:04
bunch of different random numbers. They are currently present in any form. But once we run this entire algorithm
23:11
basically we would have a sorted array where all the values are going to be sorted in ascending or descending order
23:17
depending on how we structure that. The idea is that we first take this unstructured value. We take each
23:25
individual value and then we start putting that within the given array and based off of the value coming in we will
23:32
appropriately adjust our remaining values. So if the first value is five currently the array is empty. So we
23:39
would simply just put five wherever. So in the first position next value is three. So we know that the three is the
23:45
smallest value compared to the five. So in this case we are going to have the new iteration where again this was this
23:52
happened where we did the middle value swap or basically binary search and we
23:58
were able to come up with the result like three and five. Then we had the value one. So once again we would repeat
24:04
the same process and we would have one over here. Once again we would repeat the same process and eventually we would
24:09
have 1 2 3 and five. The idea is for each of the value over here find an
24:15
appropriate value to add in this new array. But this new array is always going to be empty and then it is going
24:21
to be sorted. So we are going to be doing binary search over here. So for each of these characters because we are
24:27
doing binary search on all of them. Basically we are doing n work and then
24:32
for each of this n we are doing binary search that is log n work. So this code
24:38
block is an example of go of n log n work and this is like you you will see
24:45
lot of examples where we are multiplying the time complexities we are adding the time complexity so on and so forth. So
24:52
again you would be able to figure it out. So don't you worry about it. Now notice that this one is slightly
24:58
different. Basically we are trying to find like the result of pairs within this given array. So what we are doing
25:05
is we are running a for loop and for each of the value within that for loop
25:10
we are also running another for loop and then we are just simply printing the pairs or the results of the value but
25:17
because we are doing like the combination of each of the value with its other subsequent parts. Uh basically
25:24
we are doing bigo of n multiplied by n work. So for each individual items
25:29
repeat this n times. That is what this code block is basically doing. So we can call this big of n square time
25:36
complexity. Now big of n square if we take it like a notch further this is
25:42
like a for loop. So we have i value. Then for each of the i value we have the
25:47
j value and for each of the j value we have the kth value and we are simply
25:53
repeating like a triplet pair for this one. So this is just an extension of the
25:58
previous code block we had where we have a loop within a loop within a loop. So for each n we are doing n work and for
26:05
each of that we are also doing an n work. So basically this is going to be bigo of n cube. Now let's do some
26:12
examples of really large time complexities and this is where we are trying to calculate the Fibonacci of
26:18
this given uh through this given code block and we are doing some recursive calls back to the same function. Now
26:24
let's try to understand that what this code block is doing. Basically we are taking in a value n. We are checking
26:30
that if this value n is one then we simply return whatever the value of n is
26:35
which is 1 or zero. And if that is not the case then we are calling this
26:40
Fibonacci function again for n minus one value and we are calling this Fibonacci function again for n minus2 value. Let's
26:47
see that how this is going to go. So basically let's say that we have n is equal to 4 and we are trying to
26:53
calculate the result for this. Now four is definitely not one. So this condition would not work. So we will have to go
27:00
over here where we are going to be calling the same function fibonagi function for the value three and for the
27:07
value two. Okay. And we are going to be doing summation of these two. Now for this Fibonacci of three we are going to
27:13
call this function again with Fibonacci of two and Fibonacci of one. Now Fibonacci of one we already know that
27:19
this value is one. So that's good. We already have one result. Now for Fibonacci of two once again we are going
27:24
to call it with Fibonacci of one and Fibonacci of zero. But for Fibonacci of zero we know the value is going to be
27:30
zero and Fibonacci of one the value is going to be one. So now we have this one and zero. So combination of these two is
27:36
going to be one. So now we have this one. So now 1 + 1 we have this value as two. So now this value we received as
27:44
two. Okay. And now we also have Fibonacci of two. So Fibonacci of two is
27:49
once again going to be the value one. And once again uh this is going to be
27:54
basically zero. So this is also going to be one. So the the sum of this is going to be three. So this is the answer we
28:00
are going to return. But notice that instead of this being four, if we had value as being five, so this whole stuff
28:08
would basically increase. Now we are going to be iterating for for four and for three and for four we would be
28:14
repeating all of these things and for three we would be repeating all of these things. So it grows very large because
28:22
we are going to have a very large calculation over here and very very large calculation over here. If this
28:27
value were to be 100 then once again we will be calculating for 99 and 98 and we
28:32
will keep on repeating so on and so forth. So this is a highly inefficient solution for a very legitimate problem
28:39
and the input size doubles every time because notice that for this each number
28:45
we are essentially calculating or repeating the multiplication of same calculation again and again. So this is
28:51
an example of bigo of 2 to the power n time complexity where with each size or
28:57
each increase in n the time it takes for us to calculate this result doubles. So
29:03
this is a very expensive time complexity. And now we have one more that is even more expensive and this is
29:09
an example of basically a factorial time complexity. So let's see that why this one is a factorial. Basically we are
29:15
trying to calculate all the different permutations and combinations possible between given string as str and given
29:22
string uh an answer. And now what we are doing going to do is we are checking
29:28
that if this is this is zero then we can simply return the answer. But if that is
29:33
not the case for every single character present in str we are going to compare
29:38
that with every single remaining value within this uh substring of answer. So
29:44
this is going to become like very large very quickly and that's why this is a factorial based time complexity. Um so
29:50
this is like the most expensive one. Now let's try to put things into perspective
29:56
and uh we will see that how things change from like basically bigo of one to all the way to big go of n factorial.
30:03
Okay. So let's say that if we have bigo of one time complexity uh we are going to run a comparison table where we are
30:10
going to compare the value of if given input size is 10 if it is 100 and if it
30:16
is 1,000 and we are checking that this is basically the time it takes to run the algorithm. Now for simplicity's p
30:23
perspective let's just make sure that they are all of these numbers are in second so we can have some way to
30:29
comprehend or understand the results for constant time even if we had 10 results 100 results or 1,000 results it's always
30:36
going to take us 1 second to calculate the result because that's what it is a constant time complexity but for
30:42
logarithmic n with the increase in the size of n there would be an increase in
30:48
the time it takes to compute but notice that for 10 basically 10 inputs it would
30:54
take us 3 seconds to compute. For 100 it would take us 6 seconds. For 1,000 it would take us 10 seconds. So not a
31:00
substantial increase. Meanwhile our input actually like uh increased threefolds. Uh so 10 multiplied by 10
31:07
multiplied by 10. Uh for n it's linear. So 10 100 and 1,000. For n login it
31:14
basically takes us like multiplication of these two. So 33 seconds, 664 seconds
31:21
or 9,000 uh something something seconds for n² and n cube. It's essentially just
31:28
the square value of all of the this 100, 1,000 and 10,000. And notice that how
31:33
large it gets especially for like n² time complexities or n cube time complexities that the number keeps on
31:40
growing larger and larger. So this is a good cue to ourselves that if we have n
31:46
cq can we bring it down to n square if we have n square going can we bring it down to n or n login something like
31:51
that. So the better we can do in this regard the faster our algorithm is going
31:56
to be and for 2 to the^ n and n factorial the numbers are just out of this world like even for 10 input sizes
32:03
it takes us 1,000 seconds to solve the problem and 2 to the power n for n factorial it takes us like 3.6 6 million
32:11
seconds just for 10 inputs and for these this is like 10 ^ 30 and 10 ^ 301 which
32:17
is like huge numbers and these numbers are even larger than that. So um we
32:24
should always try to avoid these time complexities no matter what and we can there are some ways to of doing it using
32:31
like dynamic programming and greedy approach and being creative about different things. uh so we are going to
32:36
be learning that throughout this course just this is just something to keep in mind. Now let's try to understand that
32:43
what is space complexity. Once again space complexity is denoted by big O notation and it is the amount of space
32:50
required in order for us to accomplish our expected goal. So let's try to understand it with a live scenario. In
32:56
currently I have two containers. This container contains bunch of different white chickpeas and it is a white
33:02
container. And I have a black container that contains bunch of different black chickpeas in a black container. Now my
33:09
aim is to move all of these black chickpeas into this white container and move all of these white chickpeas into
33:16
this black container. How would I do that? If I only had these two containers available and if I have to do one by
33:22
one, what is going to be the algorithm that sequentially or individually I'm going to pick and choose all of these
33:28
black chickpeas from this one and keep on adding them. And then uh at the same time I'm going to be adding the white
33:34
chickpeas over here. Again, it's going to become extremely excruciatingly difficult because there are so many
33:41
chickpeas that looks pretty much the same and it's going to take me a lot of time to do it. But if I add the space
33:47
complexity or if I add one more container in between. If I just move all
33:52
of these black chickpeas like this, all of these white chickpeas like this and once again all of these black chickpeas
33:58
like this. Notice how quickly I was able to flip between the uh all the chickpeas
34:04
amongst these two containers because I had to use this extra container and how quickly this whole algorithm was able to
34:12
be finished because I'm no longer doing any kind of addition or sub subtraction in this case and that is how powerful
34:18
space complexity can be. Many times we are going to be seeing that if a problem is going into the realm of bigo of 2 to
34:26
the power n time complexity or factorial time complexity or even n square time complexity we might use an extra data
34:33
structure to store the previously computed results and that is going to
34:38
allow us to very quickly flip between our inputs and retrieve the answer very
34:44
fast and we will be able to solve pro problems much quicker and that is the whole idea of space complexity once
34:51
again it gets denoted by big O and we are going to learn a lot about them in each of the lead core problems we are
34:57
going to solve
35:04
now let's talk about the milliondoll question how do you even get good at DSA
35:11
now number one thing is practice second thing is to be able to understand all the different data structures and all
35:17
the different techniques we have and then try to look for important patterns that repeats in many cases which we are
35:25
going to be doing through lots and lots of interview examples and understanding
35:30
different patterns and third thing you need to follow the simplest strategy of
35:36
understanding the problem in the most basic terms as a nonIT non-computer
35:42
graduate person would do just try to think that how does a simple problem
35:47
that is being thrown at How would you try to understand it in your own words? Build some basic
35:53
examples and try to solve it using the most simplest terms or even the brute
35:59
force approach even if it is not optimized for speed or anything else.
36:04
Next, you will try to see if applying different data structures in any
36:10
particular questions you are given, can they be helpful in speeding up some
36:15
repetitive process. And number three thing if you have a brute force solution
36:20
that has let's say bigo of n cube time complexity your immediate aim should be
36:27
to make it better than bigo of n cq can you make it like bigo of n² can you make
36:32
it bigo of n can you make it log n so so on and so forth. So once understand the
36:38
problem in the most basic terms come to the most basic most rudimentary solution
36:45
and then see if you can improve upon that and whenever you are doing this
36:50
throughout keep your interviewer engaged in the conversation communication just
36:55
let him know that hey this is what you are thinking this is what you are doing just be as transparent as you want they
37:01
are judging you based off of do you have like proper communication skills skills and problem solving abilities and how
37:08
does your thinking works. If they see that you are tackling a problem that you are you have never seen before and you
37:16
are building like a brute force solution and then you are correcting yourself and then you are making a better solution
37:22
and if your thinking is correct there is a very high likelihood of you being selected for that next interview or for
37:29
that next job. So that is what we are going to learn. So now let's move on to the next topic. So let's try to
37:36
understand that what is the classification of different data structures. We can broadly divide data
37:41
structures into three main categories. Linear data structure, nonlinear data structure and hashbased data structure.
37:47
So let's try to understand each one of them. A linear data structure is a data structure where basically all the
37:53
elements are typically sequential. So it comes into the data structure one after
37:58
the another. Think of it all the elements being present in some sort of a line. So what are the linear data
38:04
structures? First one is an array. Array is a fixed size linear data structure that we are going to see lot of examples
38:11
of. Basically uh in the memory of the computer we allocate a fixed size block
38:17
where we can enter elements and where we can remove elements and all the elements are going to be accessed by the index
38:24
position of that particular element. Next one is a link list. Link list is completely different compared to array
38:31
where we don't have a fixed size. So basically it's a dynamic data structure. And for this dynamic data structure we
38:37
can basically have two items. We have the head of the link list and we have
38:42
the tail of the link list or the last element inside the link list. Now head of the link list points to what is going
38:49
to be the very first element inside the link list. And in this very first element basically this element is made
38:55
out of two me two chunks in the memory. First one contains whatever the value this link list persist. So it can be
39:02
integer, boolean, whatever you wants to imagine. And in the remaining portion it shows that what is going to be the
39:08
address of the next element inside the link list and next element is also formed similarly. Next element is also
39:15
formed the sim similarly and the last element that is going to be the tail of the link list. this refers to or this
39:21
points to the null variable or null pointer and that's where the link list ends. So basically link list can shrink
39:28
and grow in the size depending on how many elements are there and it can all happen dynamically. So we don't have to
39:35
worry about it. Now stack and Q they both can be formed using arrays or using
39:41
link list. Basically these two contain some special properties. So stack is a
39:46
kind of last in first out data structure where uh you can imagine this as being
39:53
stack of plates or stack of books where if you have to access the books you basically put books uh from bottom all
40:00
the way to top but when you want to get any book out first you have to get the top book out before you can reach to the
40:07
next book. So it's always going to follow this property and this can have become helpful in lot of different
40:13
scenarios and this is an example of stack. Now Q is again a complete
40:18
different or opposite concept of stack. The a Q is typically the Q that we
40:23
typically follow in any place like bank or movie theater or anywhere where we follow first in first out principle. So
40:31
a let's say that if this is the cube and we are entering from this end and we are exiting from this end. So basically
40:37
whichever the element was the first to come in in the que is also going to be the first to get out of the que. So this
40:44
is separate compared to our stack example. But basically both stack and Q
40:49
also follow the linear property where one element comes in after another element and that element comes in after
40:56
another element in some fashion. So basically this is an example of linear data structure. Now let's try to
41:02
understand nonlinear data structure. Now a nonlinear data structure is a data
41:07
structure where we don't have any sort of sequential line or sequential
41:13
property that we need to follow. Basically elements that are present inside nonlinear data structure. They
41:19
typically follow some sort of hierarchical uh data structure or they follow some some kind of networking
41:26
related data structure where one element can come in after another element that can comes in before some other element
41:32
that comes in after some other element. uh there can be all the different kinds of jumbled up uh relationship and we
41:39
need to follow that and some elements are not attached to the existing set but
41:44
they're still part of the given uh data structure or so this is an example where
41:50
this is going to be dynamic data structure that's for sure because it can grow and shrink in size uh and there are
41:56
many different ways to implementing that that we would see later in uh subsequent courses but overall there are two main
42:03
nonline linear data structure. First one is graph and second one is a subset of graph that is defined as trees. So let's
42:11
first talk about trees because this is like kind of slightly smaller compared to graphs. Uh tree is not your typical
42:18
tree. This is a different kind of tree where we we have a root variable. So
42:23
this root variable is going to be the entry point into the key tree and from there it can have subchildren or it can
42:31
have children uh of its own and there can be many different type of trees. There can be binary trees, turnary
42:36
trees, uh end trees, unique trees, red and black trees. So there are many different concepts but overall the
42:43
principle is that each element is going to be differentiated based off of its level. So all the elements that are
42:49
currently present at the bottom level these are referred to as leaf node because they don't have kids of their
42:55
own and all the elements above leaf are going to be the parents of that subsequent level. So these nodes are
43:02
going to be parents of these nodes. Once again this root node is going to be parent of the these nodes. So overall we
43:08
follow some sort of hierarchical property when we are talking about trees and it can be useful in many different
43:15
scenarios and that we will see for sure. Uh now one thing important in the tree is that all the nodes are connected. So
43:22
we don't have a scenario where there can be a node of tree that is part of this tree but not connected in some sort of
43:28
edge. So it is always going to be connected somewhere along the tree. Uh and also there cannot be any cycles. So
43:36
all the nodes are going to be uniquely defined and there cannot be cycles present inside a tree. So these are the
43:43
two main things that differentiates trees from the graphs. Now let's talk about graphs. So in the graph basically
43:50
we have two things. We have nodes and we have edges. And these nodes and edges have some sort of connection between
43:56
them. So there can be two nodes where it's possible that only one node has edge going from one place to another one
44:02
but other one does not. Some places both of them have edge going towards each other. So we can define it as two
44:09
separate edges. There can be a connected graph. So this is an example of connected graph where all the elements
44:14
are connected with each other. There can be non-connected graphs as well where some graph some nodes are connected and
44:21
other nodes are not connected. Some clusters can be connected and whatn not. So there are many different examples of
44:28
graphs as well. Uh there are direct uh directed graphs, nondirected graphs, there are weighted graphs, there are
44:34
unweighted graphs, cyclic graphs, non-yclic graphs and so on and so forth. And we can do all sorts of things using
44:40
graphs. It can be used very heavily in applications such as social networks where you have bunch of different people
44:46
who have some sort of relationship with each other. So someone is friends with someone else, someone is following
44:51
someone else and you need to define that you it can also be very helpful in defining some sort of maps where you
44:57
have a bunch of different places or cities and then there are roads going between those cities. So how you can
45:02
connect that, how you can find the shortest path and things like that. So again graphs is also very powerful and
45:08
very useful in lot of different cases. And last uh last data structure we have
45:13
is going to be hashbased. Now inside the hashbased data structure we have some sort of hash that defines every single
45:21
element that is currently present within the the hashmap or hash set in very
45:27
quick manner. So we can identify and pick out elements very quickly in
45:32
basically near constant time. So why this is useful? Because if we talk about
45:38
some data structure, let's say array or trees or anything if we have to find any
45:43
particular element worst case scenario we might have to iterate over entire array or entire tree before we can find
45:48
that element. But if we have a hashmap or hash set, we can virtually find that
45:54
element in goof one time. And why this works? Well, basically we let's first
46:00
try to understand hashmap. So in the hashmap we have something called key value pairs. So anything or any value
46:06
that we try to insert within the hashmap is going to have two elements. A key associated with that and then and then a
46:12
value associated with that. Let's try to understand a very simple and basic key. So we will try to determine that what is
46:19
going to be the starting alphabet of any particular character. So let's say if element starts with a we are going to
46:25
define key as a and then add the value as apple. And for simplicity we are making sure that we can only have values
46:32
from A to Z and each are going to have just one unique value. So same way for B we can have a value for ball and
46:38
whatever and whatn not. Now if I am trying to determine that whether bat is currently present inside this hashmap or
46:44
not I don't need to scan all 26 values that are present. I can very quickly go to this element where the B is present
46:51
and check that what is the value associated with that. And currently because this value is ball and it's not
46:57
bad. I know for a fact that bad is not present. So I can return this answer very quickly. This is the advantage of
47:03
hashmap. Now it could be possible that if we just have one key and we want to add multiple value, we can put some sort
47:10
of link list over here. But there is there are going to be advanced concepts that we can take about think about it
47:16
for simplicity. Let's try to understand that we have some sort of mathematical formula that different that uniquely
47:23
defines any single element within the hashmap. So for each key like in theory
47:29
we only have one value associated. If that's the scenario no matter if we add million keys over here basically we can
47:35
find any particular value in very quick time and very quick fashion. The what
47:40
are some of the downsides? Well we cannot have duplicates values uh because all the duplicate values are always
47:46
going to end up within the same key value pair. So it we can't have duplicate values being inserted within a
47:52
hashmap and that is also true for hash set. Now the difference between hashmap and hash set is that again for all the
47:59
elements that are present in the hash set they also get stored but we don't store any particular key for them. We
48:06
only store the value and we can check that whether this value is currently present inside the hashet or not or we
48:12
can add the value inside the hashmap and all the operations are very quick. they happen in virtually we go off one time
48:19
but again there are differences and some trade-offs we will have to make sure if we are working with hashmap or hashet
48:25
and we are going to be seeing plenty of examples of these as well throughout the courses so don't worry about it if you
48:30
don't understand so I hope this all makes sense to you and now you have some clear understanding that what each of
48:36
these data structure means.
48:45
So now let's try to do a quick recap. We first understood that what is data structure and what is algorithm. Then we
48:51
understood that how to judge an algorithm. What is time and space complexity. Then we understood that what
48:57
are the different categories of different data structures. And now we will start getting into the meat of the
49:03
actual course. So we are going to go with the 20 topics that I discussed earlier. For each of the topic we will
49:09
understand that what that topic is. What are the different common operations, patterns, use cases associated with that
49:17
topic and then we will start solving many most task most like and most popular lead code problems or technical
49:23
interview problems associated with that problem. That is how you get good at
49:28
tech solving technical interviews and building your intuition for solving the problem. So I know it's not going to be
49:35
easy. It's definitely not going to be entertaining. uh it's going to be very boring in some cases but you just have
49:42
to have the perseverance because if you go through this whole process and
49:48
actually become better at your technical interviews you can change your lifestyle within 3 to 6 months like completely
49:55
different compensation completely different bracket different country different company whatever so
50:01
motivations are huge benefits are tremendous and it's just a long journey that you have to endure so I wish you
50:08
best of luck. Now, if you made until this part of the video, just comment the word pineapple because I like pineapple.
50:15
I hope you also like pineapple. Who doesn't? And uh without any delay, let's get started.
50:27
Hello friends, hope you're having a fantastic day today. So now we are going to learn an entire full course on array
50:34
as a data structure. By the end of this course, you should be an expert in all the questions related to arrays.
50:42
First, let's try to understand that what an array is. Array is nothing but a continuous block of memory that is
50:49
currently stored inside your computer. Now, inside this continuous block of memory, you can store integer data type
50:55
or boolean data type or string, character, whatever you wants to put, you can store these values. But arrays
51:02
have some restrictions and some properties. Number one restriction in an array is that it is a fixed type of data
51:08
structure. So whenever you are storing the information you need to define that what is going to be the size of this
51:14
array. So currently this array that I have provisioned can only hold up to five distinct values. Second thing is
51:21
everything inside the array is defined by its index positions. So in this case
51:26
for this array uh the index values would be defined as 0 1 2 3 and 4. On top of
51:33
it because this is a fixed size and also all the values are continuous in nature. I can fetch any particular index
51:40
position values in constant time. One of the other thing is uh computer knows
51:45
that what is going to be the memory size for each of these blocks. So let's say that this block cost 8 bytes of memory
51:53
inside to be stored inside the computer. Also computer knows the starting position of this uh this particular
51:59
memory location. So let's say that inside the memory of computer this one is defined by 1600. So logically if we
52:06
have to access this value the position is going to start from 1608. Same way
52:12
position for this is going to start from 1616 and so on and so forth. So that's
52:17
why this makes array unique and fast in terms of nature.
52:23
Now let's learn that what are the different array operations that we can perform and also what are going to be
52:29
its time complexities. So first operation that we would like to see is access that let's say that if there is
52:35
some element that resides at position number two or position number three how quickly can we access? We just explained
52:41
that this can be done in big of one time and fetch the value that we are looking for for the insertion. Typically the in
52:48
normal scenario this works in big of one time but worst case time complexity can be big of n because we are trying to
52:56
find a space where we need to insert the value. So if is it is a random insert that we don't know that whether we have
53:02
an empty space or not or if we are trying to make frequent modifications we might have to shift values inside the
53:08
arrays as well. uh same goes for the deletion that because we are deleting some elements from the array we will
53:14
have to shift the cells here and there. So in that case worst case scenario it can be big of n but typically most of
53:20
the languages handle these scenarios uh in relatively simple fashion and average scenario is going to be big of one for
53:27
both of them. Now traversing an array is very straightforward. You simply start
53:32
from uh the starting pointer and keep going in one direction until to you reach to the very end of the size of the
53:38
array. And this can typically be done in big of n time where n is the total number of elements present because we
53:44
will have to iterate over every single element in order to access them. Searching is also quite an interesting
53:50
one. Let's say that currently this array contains uh five different elements and
53:55
you are trying to search that whether any particular element uh resides inside this one or not. Let's say that you are
54:02
trying to s see that whether element number zed is present or not. So in this case uh if this values are not sorted
54:11
and these are random values then you must do a linear search and a linear
54:16
search is only going to yield big of n result because you will have to reach or search every single value or you can do
54:23
something called a binary search if the given values are sorted. So you can see in this case the given values are sorted
54:30
lexographically. So we can actually apply binary search in this case and we can solve this
54:36
problem in big of log and time and don't worry about these things you are going to see tons of examples of these things
54:43
in action. So it it would become a second nature to you and last one is an update. So if you have to update any
54:50
particular element let's say that instead of this x I want to update this value to be m. So I can do this
54:58
instantly because I can reach or fetch that element.
55:05
So number one benefit of an array is that we are dealing with random access time complexity of bigo of one. So if we
55:13
have to access multiple values from the array, we can do it in big go of one fashion that this is going to be really
55:19
helpful in certain scenarios. Next thing is array is a wonderful cache friendly
55:24
data structure which means you can see lot of different operations where array
55:30
becomes a supporting data structure for the main problem we are trying to solve. We can use array very heavily in dynamic
55:37
programming problems. We can use array with graphs, trees and all the other data structures to in order to store
55:43
some valuable information that we are trying to memorize or using using it by
55:48
tabulation. Next thing is we can very easily sort values inside the array. And
55:54
next thing is uh array is very popular in implementing other data structure.
55:59
You can implement heap, you can implement tree, you can implement uh link list, you can implement stack, q,
56:05
all of these things using different uh ways to modify and manipulate arrays. So
56:10
arrays are overall very diverse data structure. Now let's see some limitations. Number one is because
56:16
arrays are fixed size there is only so much you can do. If you're dealing with some dynamic problem where the value are
56:23
continuously increasing and if you're trying to use array then it becomes obsolete because every time uh you are
56:29
going to be facing an issue where array runs out of the size. So you can only use array until uh you know for sure
56:35
that the the size is going to be fixed. If you have to deal with dynamic uh scenarios you can use something called
56:42
array list where inside the array list it helps with like dynamic nature but there is a whole separate discussion on
56:48
its own. Next thing is uh for typical insertion and deletion worst case
56:53
scenario it can go into big off if you don't know where you are trying to uh insert those elements or delete those
57:00
elements from and next thing is that it is very in inefficient in terms of frequent modifications.
57:08
Now let's see that what are some of the common use cases where you should start think about using array for various
57:16
different uh purposes. Number one use cases that I just explained is to implement other data structures because
57:23
array is simple and can be modified in many different ways. Next thing is
57:28
whenever you see any kind of caching in uh or tabulation or memoization item
57:34
that you need to perform you must start to think about using an array. Third
57:39
thing is whenever you are dealing with graph problem or tree problem and you need to keep track of visited nodes then
57:45
you can also think about using an array. Then whenever you need to do some sort of mathematical computation you can also
57:51
use an array. And uh one good thing about array is that it has lot of
57:56
popular coding patterns. So coding patterns such as two pointers uh sliding
58:01
window technique then a fast and slow pointer and all of these things can be used in many different ways that can
58:08
become really helpful and we are going to see all of these in action when we do our 25 most popular most asked
58:14
questions. Now arrays also comes in multiple
58:21
dimensions not only one dimension. So far we have seen all the arrays that typically looks like this where we can
58:28
define this as one dimensional one-dimensional array where you can notice that every single cell only is
58:35
being defined by one particular index position. Now there can be scenarios
58:41
where we need multiple categorizations to define any particular cell value and
58:46
for that we can actually use multi-dimensional array where this is an this would be an example of 2D array.
58:52
Same way we can have a 3D array, we can have a 4D array. So let me give you a common scenario. Let's say that I just
58:59
want to say that whether any particular student is present or not. So I can create an array like this where I'm
59:04
storing a boolean information and in each of the scenario I am marking all of
59:10
these values based on the student role numbers or ID numbers. So this becomes a one-dimensional array problem that I can
59:16
solve easily. But now I want to create a matrix of information such as uh grades
59:24
for every single student on top of it their role number. So uh I want to
59:29
define each of the cell based on their grade and role number. So I can create one entire section of grades starting
59:37
from A to F. And same way I can have another section for role number starting from 1 2 3 all the way up to N students.
59:44
Now any particular cell in this position is going to define that this cell defines that for role number three
59:50
whether that student got B grade or not. So this can be another way of categorizing values and this also
59:59
contains the same property of fast access and all of the good stuff that ar has to offer. So typically for any DSA
1:00:07
problem and uh technical interviews we are only going to be dealing with 2D arrays but in theory and also in
1:00:14
practice we see all the time 3D and 4D arrays as well. 5D arrays very rarely
1:00:20
but uh this is something to just understand.
1:00:26
The read code problem we are going to solve now is called two sum. This is the number one problem on the lead code and
1:00:32
we can see that this one is an easy problem and also the most like problem on lead code. Let's understand the
1:00:38
statement. Basically we are given an integer array nums and we are also given an integer called target. Now we need to
1:00:45
return the indices of the two numbers within the nums array such that they are
1:00:51
the sum of target. So basically they add up to the value target and we are guaranteed that there is always going to
1:00:57
be one solution and we can return these indices in any order. So let's try to
1:01:02
understand this with an example. We are given an input error nums over here and we can notice the values are 15 7 2 and
1:01:08
11 and we are also given target value to be nine. Now in this example we can see that the 7 and two sums up to target
1:01:15
value number 9. Now if we see the index positions of the 7 1 um sorry 7 and two
1:01:21
uh they are located at basically one and two position. So we can return the answer as one and two or we can also
1:01:27
return two and one whichever like sequence we want but basically this is what we need to return. Now let's
1:01:34
understand that what are the different ways we can actually find the sum of these two values. So first let's
1:01:40
understand the brute force approach. Basically for the same example let's say the values we are given we are going to
1:01:47
try every single permutation and combination. So what we will do is currently this value is 15 and the
1:01:53
target we wants to make is 9. Okay. So this value is 15. So we cannot use any
1:01:58
other value to basically form the target value as as 9. So we can just ignore this case. Okay. Now this value is
1:02:05
seven. So because this value is 7, the total target we wants to build is 9. So what we'll do is we'll do 9 minus 7. So
1:02:12
we will check that if the value two is present inside the remaining area or not. And lucky for us the value two is
1:02:19
present. So we can just return basically the index positions of this these two. Now notice that um in the brute force
1:02:27
approach what we are essentially doing is for every single character in the
1:02:32
worst case we might have to iterate over all the remaining characters to see if any particular value is present or not.
1:02:38
Let's take an example that if this value was to one then we would have to check that whether 8 is present. So for that
1:02:44
we might have to basically go over all of them. So the time complexity would have been big of n² that is a bad time
1:02:51
complexity. Now let's see that if there is any particular way we can improve upon that and the answer is yes. We if
1:02:57
we do sorting basically things would become slightly better and easier. How?
1:03:04
Let's understand that for the same example if the values are 15 7 2 and 11.
1:03:09
Once again if we sort these values we would be left with value 7 uh sorry 2 7
1:03:15
11 and 15. Now uh we are at value number two. Okay. So notice that if uh the
1:03:22
target we are going to we want to generate is 9. If we already have value as two which means uh if we do 9 minus 2
1:03:29
the answer becomes seven. Now all we need to do is to check that whether seven is present inside the remaining
1:03:35
area or not. Same as our brute force approach. But in this case because we know that this is already sorted instead
1:03:42
of using linear search where we are iterating over all of these values one by one we can use binary search and that
1:03:50
would help us alleviate lot of questions because in the binary search remember that we will find the middle value. So
1:03:57
let's say we find middle value is 11 in this case and from 11 we know the value
1:04:03
we are trying to build is seven. So the even if there were like 100 elements on
1:04:08
the right of 11 they will all be smaller or sorry greater than seven. So we
1:04:14
cannot use them. So we will just ignore the entire right portion and only limit our search to the remaining piece and we
1:04:20
would be able to find the remaining value in essentially log end time which is exceptionally fast. So this if we see
1:04:27
like the sorting approach of sorting the original input array things becomes quicker. Um and we can actually solve
1:04:34
this problem in big go of n log and time and this is the time to basically sort
1:04:39
the given input plus login time to find any particular character. But the thing
1:04:45
is we generically we can just write it we go of n login as the overall
1:04:50
solution. Now the question is is there a way to do things quicker and the answer
1:04:56
is yes. We can even do things faster if we use an additional data structure in
1:05:02
this case. And uh let's see what are the considerations for us to understand any
1:05:08
particular data structure. Number one thing is whenever we see a value we are
1:05:13
trying to basically determine that what is going to be the remainder. So in order to quickly look up that do we have
1:05:20
that remainder or have we already passed that remainder or not uh what we can do is we can use a hashmap in this case.
1:05:27
Now notice hashmap contains two properties. First thing is a key and
1:05:33
second thing is an appropriate value. Now as part of the key we would put
1:05:38
whatever the array item that we currently have. So let's say that we are given uh once again this array as an
1:05:46
example. Okay. Now in this case we once again need to return the target value of
1:05:51
let's say 9. Uh so now in this case uh what the algorithm we are going to use
1:05:57
is first we'll iterate over any particular character inside the given nums array. For that character we will
1:06:04
see that what is the remainder value we are trying to generate. So for this value number one we know that the
1:06:10
remainder value should be eight. The question is is 8 present inside the hashmap or not? If it is not present
1:06:17
that's it. We simply add this value one saying that it could be potentially a
1:06:22
match for some future target value that we are trying to generate and continuously we will keep on doing that.
1:06:29
So as a key we will add value one over here and as its appropriate value we are
1:06:34
going to store the index position. So index position for this one is going to be zero. So we will store value zero
1:06:40
over here. Now let's repeat the same operation. Now next value is value number seven. So for if we already have
1:06:46
a seven to be part of the two sum that we are trying to generate we will need to have 9 minus 7 which means value
1:06:54
number two as part of the hashmap. But currently hashmap does not have value number two. So what we'll do is we will
1:06:59
simply add value number seven with its index position as one. Same way we have value number three. If three were to be
1:07:06
part of the answer we we need to find value number six. Six is not present inside the hashmap. So we will simply
1:07:13
add three over here with its appropriate subsequent value that is index position number two. Now we are at value number
1:07:19
two. For two we need to find value number seven. And lucky for us seven is
1:07:25
present with within this hashmap and we already know its subsequent value is one. And we are since we are already at
1:07:31
two we know the index position of two as well. So in this case we can return the answer as let's say 3 and 1 or we can
1:07:38
also return like 1 and three whatever we want. But basically this is the index position of the values that basically
1:07:46
sums up to total value number nine and this is the fastest way to solve this
1:07:51
problem. Now let's analyze the time and space complexity. Time complexity is going to be much faster of n. Why?
1:07:58
Because we are iterating over all of these elements just once and we are coming coming up with the solution
1:08:04
because remember searching that whether any particular value is present inside the hashmap or not happens in big of one
1:08:10
time which is significantly faster than everything else. Let's analyze the space complexity. So space complexity is going
1:08:17
to be big of n as well because we have to use an additional hashmap to store the results. But needless to say this is
1:08:23
much quicker than both our brute force and also our sorting approach. So now let's see the coding approach for this
1:08:29
one. So the coding solution is quite straightforward. First we are going to initialize a hashmap to store all the
1:08:36
values and their index positions. Then we are going to iterate over the given input array nums. And for each of the
1:08:42
array we are going to calculate that what is the remainder value in a variable called complement. Then we are
1:08:48
going to check that if that complement is already present inside the hashmap or not which we can do in big goof one
1:08:54
time. If the value is present, we simply return uh a new array that contains the
1:09:02
value of the comp that that particular key and the current E position. These are the two index positions. If we do
1:09:09
not find that value, we simply uh add this current number that we are
1:09:14
iterating over within our hashmap using map.put. And uh in the end, we simply
1:09:19
return an empty array if no solution is find found. But this wouldn't happen because uh in the problem we are already
1:09:26
told that there is always going to be exactly one answer. We are just putting this return statement. So we don't get into a compile time error. Okay, let's
1:09:34
try to run this code. Okay, seems like our solution is working
1:09:40
as expected. Let's submit this code and we beat nearly 99% of all the other
1:09:48
solutions which is awesome. And uh in terms of memory usage, we can improve if
1:09:53
we use some other solution. But this is also needless to say a very good time and space complexity. And this is the
1:10:00
most popular problem. So you must know it by heart. Uh once again the coding solution is present in our GitHub
1:10:06
repository. So feel free to go and check it out from there. Thank you.
1:10:18
So the lead code problem we are going to solve now is called contains duplicate. We can see that this one is a lead code
1:10:23
easy problem and also an extremely well-like problem. The statement is quite straightforward that we are given
1:10:29
an integer array called nums. Now we need to check that if there exist any
1:10:35
particular value more than one times uh at least twice then we need to return true saying that yes there exist
1:10:41
duplicates in the given array and if it does not exist we need to return false. So let's try to understand this with an
1:10:47
example. Suppose this is the input array we are given. Now we can notice that value four appears twice in this case
1:10:54
which means there exists duplicates in this given input array nums. So we need to return true in this case. Now if say
1:11:01
for an example we are given one more nums array and all the values are unique or we don't see any duplicate values. So
1:11:08
basically in this case we can return false saying that there does not exist any duplicate values and the statement
1:11:15
is very simple to understand. Let's see that what is going to be the most common brute force approach we can use to solve
1:11:21
this problem. We will take the first value and we would check against every
1:11:27
single other value possible that whether one is present or not. We identify that
1:11:32
one is not present. So in this case now we would move on to the next value two and once again repeat the same
1:11:37
operation. For three repeat the same operation and at the four we would realize that there exist one value four
1:11:44
that is being repeated. So basically found a duplicate. So we will return true in this case. And say for example
1:11:50
if we don't find duplicates and we return we reach to the end of the array then we can simply return false saying
1:11:56
that there does not exist any duplicate values you straight away you can see that what is the issue with this
1:12:01
approach. Well the idea is that for any particular n value or any particular
1:12:07
work we will have to repeat the same operation for every single other values which means the time complexity is going
1:12:14
to be bigo of n² which is definitely pretty expensive. uh and there are ways
1:12:20
to make it faster. So the first optimal approach that comes to our mind is uh basically sorting. If we can somehow
1:12:27
sort the given input array then things would become much easier. Let's say that we are currently given an input nums and
1:12:34
the values are scattered all across the place and we can find that there are some duplicate values over here as well.
1:12:41
Uh if we sort this given input array then the sorted input is going to look something very similar. uh and then for
1:12:48
the sorted input all we need to do is just keep checking all the values with
1:12:54
its like uh next value or previous value and uh over here after one we find value
1:13:01
number three which means it is not possible to have one in the remaining array because this is a sorted array.
1:13:07
Same way for three we found value number five which means there is not possible to have another three inside the
1:13:12
remaining array. But for five because there there exists a duplicate it has to be very next to it. We found a duplicate
1:13:19
and we can simply return true in this case very easily. Now this is a much better approach than our brute for brute
1:13:25
force approach. But let's see that what is going to be the time complexity. Well, it is going to be big of n log n
1:13:31
because it takes n login time to sort the given input array. And the question is is there a way we can do something
1:13:38
better? And the answer is yes. The fastest approach in this case is going
1:13:43
to involve something where we need to keep track of all the elements that we
1:13:49
have already seen and we should be able to access them quickly. And these are
1:13:54
the two uh basically conditions that we need to follow. And for that the best
1:13:59
data structure in this case is going to be a hash set that it cannot contain duplicate values and it is it basically
1:14:07
finds any particular element inside the hash set in we go of one time. So suppose this is the array we are given
1:14:13
as an input. Now what we will do is that we will iterate over this array and for every single value first we will check
1:14:19
that whether this value is present inside the hash set or not. If it is not present, we will simply just add it to
1:14:25
the hash set and it move to the next value and repeat the same process. So let's see that how would that work and
1:14:32
let's say that this is going to be our hash set. Okay. So first we are at value number three. Currently value number
1:14:37
three does not exist inside the hash set. So we will simply add value number three and move on to the next value.
1:14:42
Once again value number one does not exist. So once again we would add value number one. Uh now four four also does
1:14:48
not exist. And now once again we would move to value number one. Again at value number one we would check that whether
1:14:54
this exists inside the hash or not and yes it does exist inside the hashet and we can check that in big go of one time
1:15:00
which is awesome. So in this case we can say that because there exist a value that is already present inside the
1:15:07
hashet that we are trying to add to the hashet which means uh the given array contains duplicate. So in this case we
1:15:14
can simply return true and say for some reason this value one is not present over here and let's say that this value
1:15:20
is maybe six. So six currently does not exist inside the hash set. So we will add six over here. Once again we are at
1:15:26
value number five. Five also does not exist. So we will add five to the hash set. And now we have reached to the end
1:15:31
of the array. So if we reach to the end of the array we can simply return false saying that there does not exist any
1:15:37
value that is duplicated. If we see time complexity in this case the time complexity is going to be bigo of n.
1:15:43
Why? Because we are simply iterating over the given input array once and for
1:15:49
every single value even though we are checking that whether it's present inside the hash set or not it can be
1:15:54
done in big of one time that is the power of hashing functions like hash set and hashmap. And uh if we see space
1:16:01
complexity, space complexity is going to be of n as well because we will have to use one more hash set to store all of
1:16:08
these variables. But still we this is much better compared to our brute force approach that had the time complexity of
1:16:14
basically big of n square. So now let's see the coding solution for this one. So
1:16:20
the coding solution is going to be quite straightforward. First of all, we are going to initialize our hash set uh that
1:16:26
we are going to keep track of the scene numbers. Then we are going to iterate over every single element that is
1:16:31
present inside the nums array. And for each of those elements we are going to check that if our hash uh set contains
1:16:39
that particular number or not. If it does contain then we can simply return true saying that we have detected a
1:16:46
duplicate. If it does not contain that number already then we will just simply add that number. Say for an example, if
1:16:52
we end up iterating over every single element in the array and we reach to the end of the array, which means there are
1:16:57
no duplicates. So we can simply return false. Let's try to run this code.
1:17:04
Okay, seems like our solution is working as expected. Let's submit this code.
1:17:11
And as expected, code runs beautifully. It beats nearly 90% of all the other solutions that are present on the lead
1:17:17
code, which is pretty awesome. And uh the solution of this code is present in our GitHub repository. So feel free to
1:17:24
go and check it out from there. Thank you.
1:17:32
Okay. So as an example, we are trying to solve the contains duplicate 2 problem. Now this is a very popular lead code
1:17:39
problem that has been asked in some of the popular companies like Amazon, Facebook, Adobe, Microsoft, Uber,
1:17:44
Google, Bloomberg, Airbnb and plentier. So these are all tech giant companies who love asking this question. So that
1:17:50
is why I considered this one. Let's try to see the problem statement. The problem statement is actually quite simple and this is a lead code easy
1:17:56
problem and also a very well-like problem on lead code. Basically we are given an integer array called nums or we
1:18:02
are going to denote it as n that contains array values. We are also given a value k and k can be anything like 1 2
1:18:10
3 4 any single integer value. So suppose k is equal to three. Now we need to return true if there are two
1:18:17
possibilities. The first possibility is there exist any two values I and J that
1:18:22
are uh exactly same. So if there there exist two duplicate values in the array.
1:18:29
And the second portion is that the difference between I and J. So I and J
1:18:34
refers to the index positions of every single value uh inside the given array. So the index position should be actually
1:18:42
less than the value of k. Let's try to understand this with few examples. So suppose our given input n is equal to 1
1:18:48
2 3 uh 1 5. If this is the input we are given and we are given the k value to be
1:18:54
four. If this is the case does it satisfies these two properties. So first
1:18:59
let's see okay so we need to check that between the window four there needs to be two duplicate values. Currently we
1:19:06
can see that there exist a duplicate value 1 and 1 over here. Let's see the index position 0 and 3. So if we do the
1:19:12
difference 0 minus 3. So basically we need to do the absolute difference. So the answer is going to be three. Three
1:19:18
is actually less than the value of four. Which means this one currently contains the duplicate value that is not far away
1:19:26
from four elements from each other. So in this case we are going to return true. Let's try to understand it with
1:19:31
one more example. Suppose our given n is equal to 1 2 3 1 0 something like this
1:19:37
and our given k value is equal to 2. If this is the case again same scenario we
1:19:43
have the values located at index position 0 and index position three that contains the same value but current k
1:19:49
value is equal to two. And if we do the difference between these two values the current difference between indices is
1:19:56
three. Meanwhile, our given K is equal to two. Which means in this case, we need to return false because there does
1:20:02
not exist any two duplicated values that are two steps away from each other or
1:20:07
between two elements of each other. So this is the whole ask. Now let's see that what is going to be the simplest
1:20:13
approach we can take. Okay. So suppose this is the input we are given. Now we let's see the brute force way to solve
1:20:19
this problem that we pick any element then we take the we check the next k
1:20:24
elements. So in this case currently we are allowed to check up until this point. So between these portions we
1:20:32
check that whether zero is present in any other value or not. If zero is not
1:20:37
present we can define that zero would not be any would not be a duplicated
1:20:42
entry in any of the uh window because we are strictly told that we can only check
1:20:47
next three elements. So in this case we can get uh rid of zero because zero is not present. Same way we are going to
1:20:54
check for value number five. So currently value number five is located at index number one which means we have
1:20:59
the ability to compare between these portions. So again for value number five we are going to check this value this
1:21:06
value and this value and bingo we find value number five. So we can return true in this case because element number five
1:21:12
exist and the difference is less than three. But this is like a very inefficient approach. Why inefficient
1:21:18
approach? Say for an example this entry does not contain any duplicated values
1:21:23
and all the values are unique and at the same time we so what would what we would do is for every single element we would
1:21:31
compare it with the next three elements and we would keep on repeating the same process until we reach to the end of our
1:21:38
loop and that would be an inefficient approach because the time complexity would be big of uh n so n is the total
1:21:46
number of elements multiply by k And this is not what we want. We want something more efficient. So let's see
1:21:52
uh an more efficient and better approach. A better approach is that we know that for any single value we need
1:21:59
to check in the remaining portion whether that value is present or not. So currently we can break it down in a in
1:22:06
this sequence. So currently we can create a window of window like this 0 and then 5 2 7. Currently we are at this
1:22:13
position number zero. Now we need to check that whether zero exist in the remaining three entries or not. First
1:22:19
approach is is to do binary search. So for binary search what we would need to do is we would need to sort this given
1:22:25
input. And if we sort this input array the sorted result is going to look like this 0 2 5 and 7. And then all we need
1:22:33
to do is check any two consecutive values. If we identify that there exist like a backto back entries that contains
1:22:41
the same value then we can return true. If it does not contain then we can move on to the next window. And again in the
1:22:48
same way we would repeat the same process for this next window that is
1:22:53
currently comprised of the values 5 2 7 and 3 and again okay. So let me fix this
1:22:59
one. So this one should be 57 and 52 53. So again if we sort this window in this
1:23:04
case the answer we are going to get is 2 3 55 and we found two backto-back values that contains the same same uh value. So
1:23:12
in this case we can return true. But the thing is even this approach is also not very efficient because uh if we see time
1:23:19
complexity in this case the time complexity is going to be bigger of n then log of k. Why log of k because for
1:23:27
any given input we will actually have to sort this and sorting it cost us lot of time and energy and uh this is also this
1:23:35
is better than the brute force approach but still there there can be improvements made. So what is one improvement we can make and again
1:23:42
remember we are using sliding window because we know that we need to do this in any subsequent values and we need to
1:23:49
find the answer. So definitely you understand by seeing the problem that why we need to use the sliding window.
1:23:56
But let's see that what would be the improvement we can make. First thing we need to check is that in the binary
1:24:02
search approach what we had to do is we need to check that whether in the remaining portion does the same element
1:24:09
exist or not. And also at the same time we were considering that every single
1:24:14
time we need to create a new window we would have to do the entire sorting calculation again. So we need a data
1:24:22
structure that can very quickly like get rid of elements and add new elements at
1:24:27
the same time very quickly search that whether the existing element exist or not and the wonderful answer for this
1:24:36
type of scenario is a hashmap. So we can create like a hashmap or a hash set
1:24:41
inside our input and hashmap and hash set are wonderful at doing two things
1:24:47
like doing the search and remove and input operations in big of one time. So
1:24:52
hashing is really good in that also at the same time it does not allow duplicate entries. So no duplicate
1:24:58
duplication is allowed which means we can identify duplicate entries very quickly very efficiently in any any sort
1:25:05
of hashing input. So we are going to use this property combined with sliding
1:25:10
window approach to solve this problem in the most efficient manner. Let me quickly show. So first we are given the
1:25:16
value of K which means we are going to create our window. So currently we let's
1:25:21
just create a window of size K. Okay. So starting from value number 0 to value number five and then we will have all
1:25:28
the values 0 5 2 and uh okay let me just put down some different value over here.
1:25:39
and let me put five over here. Okay.
1:25:45
And then this is going to be four. Okay. So this is the current these are the current values at the moment. We are
1:25:50
going to initialize a hashmap. Now inside this hashmap we are going to store two items. We are going to store
1:25:56
the value as the key and we are going to store the indices based on its value
1:26:02
inside the hashmap. So first we are going to check okay this one is value number 0 and currently the index values
1:26:07
are 0 1 2 3. So 0 is not present in the hashmap. We will add entry 0 over here and its index value zero as well. Again
1:26:15
five is also not present. So we will add entry five over here and its index value one over here. Two is also not present
1:26:21
so two and two and again four is not present so four and uh the index value is three. So we add these four entries
1:26:28
in our hashmap. At the same time we would we can check that currently since
1:26:33
the value of K is equal to three we already added four elements and still we
1:26:38
were not able to find any duplicate entries which means we will have to update our window. So in order to update
1:26:45
our window rather than getting rid of all the items what we can do is we can just get rid of the first element and
1:26:52
then we can just shift our window to include one more entry inside our input
1:26:57
and that is going to be value number five for the index value position number
1:27:02
four. So again we add five over here. At the same time since we got rid of the first index value we are going to also
1:27:09
get rid of that inside our hashmap. So we are going to get rid of the first entry and currently we have three
1:27:14
entries. Again we will try to check that whether five exists or not. So we will try to input five inside our hashmap but
1:27:20
we would be able to immediately find that five is already present as a value inside our hashmap. And immediately we
1:27:27
can return true saying that this contains duplicate inside a k window.
1:27:32
And see what we did is that initially our window was consisting of this value
1:27:38
number zero. We got rid of the only zeroth value. We kept the remaining
1:27:44
values inside our window and we simply added a new value inside our hashmap.
1:27:50
And then we were we were able to immediately identify that whether this is the correct response or not. And say
1:27:56
for an example if somehow this value is not value number five, this is value number 11 or something else, this does
1:28:02
not contain any duplicate entries. What would happen is that every single time we would get rid of the last element
1:28:08
from our hashmap and we would keep on adding new values to our window and eventually we would reach to the end of
1:28:14
our uh input and if we don't find any answer we can simply return false in this case. So if we see time complexity
1:28:21
in this scenario the time complexity is actually going to be bigo of n only and since for this case we used to we had to
1:28:28
use a hashmap of size k we the space complexity is going to be bigo of k but
1:28:34
this is a very wonderful and beautiful approach to solve this problem. So that is why the sliding window technique is
1:28:41
really powerful because you are already building your solution upon the already
1:28:46
calculated computed values. you are not doing everything from scratch and uh
1:28:51
that is very powerful in making your uh inputs more efficient.
1:28:57
Okay. So for this problem I'm not going to write the entire code. I'm just going to give you the explanation. So first we
1:29:02
are going to initialize our hashet and I mentioned that we can use hashmap or hashet anything. In this case we are
1:29:08
using hash set. Now we are going to iterate over the given input array using a for loop. First thing we are going to
1:29:14
do is to check that whether our set contains the current value, current i position of value we are at. If that is
1:29:20
the case, we can return true immediately. If that is not the case, we would add that entry to our hashet. At
1:29:25
the same time, we would check that if the current size of hashet if that is greater than our given input k. If that
1:29:31
is the case, then we need to remove the earliest entry inside our hashmap. And
1:29:36
we can calculate that using the number of e index that we are currently at minus the value k. And then if we remove
1:29:43
that values from the hashet, our hashet is only going to contain uh only the k
1:29:48
elements. And then we can keep on repeating the same process until the very end. If we haven't returned true by
1:29:54
then, we can return false in the end. And this is going to be the whole whole solution. Let's try to run this code.
1:30:01
Seems like our solution is working as expected. Let's submit this code. And our code runs decently efficiently
1:30:07
compared to a lot of other solution. And uh I would be posting this in the comments so you can check it out from
1:30:13
there. Thank you.
1:30:23
So the lead code problem we are going to solve now is called valid anagram. We can see that this one is a lead code
1:30:29
easy problem and also an extremely well-like problem. Basically we are given two strings s and t. Now we need
1:30:36
to return true if T is an anagram of S and false otherwise. Now what is the
1:30:42
definition of an anagram? Basically if every single character that is currently
1:30:48
present in T is also present in S, then they are anagram of each other. Not more
1:30:54
not less. So let's try to take an example. Suppose in this case we can see that currently S has the words cat and T
1:31:01
has the word tech. Now we can see that C is present on both. So that's good. Same
1:31:07
way A is present on both and same way T is present on both. So we can say that in this case S and T are anagram of each
1:31:13
other. So we can return true in this case. Now if we take one more example, we can see S contains R. T also contains
1:31:21
R. So that's good. S contains A. T also contains A. But the thing is currently S
1:31:27
has M that is not present inside the T. So in this case we can say that T is not
1:31:32
anagram of S. So we can return false. And basically this is what we need to return. So let's try to see that what is
1:31:40
going to be the most common brute force approach to solve this problem. Suppose we are given S is equal to RAT and T is
1:31:46
equal to tear. Okay. So in this case as part of the anagram what we'll do is we'll take a character inside the S. For
1:31:54
this we will iterate over every single other remaining character inside the T
1:31:59
to make sure that whether that character is present or not. If it is present we can remove it from here from both sides.
1:32:06
Same way we will repeat the same operation for all the all of the different characters and we will come to
1:32:12
the solution. Now if you see this approach would yield correct result. But thing is if you see time complexity
1:32:18
basically it's going to be big of n² because for every single character present inside the s we will have to
1:32:24
check against all the remaining characters inside the t which can be quite expensive. So this is like a bad
1:32:31
approach. Now let's see that what would be the optimal solution in this case and the logic is that first of all we will
1:32:38
have to check that if the given S and T if they are to be anagrams of each other
1:32:43
basically their length has to be same. So first thing we will check is that if the length of S and T if they are same
1:32:50
that's good then only we will proceed. If they are not same we don't even have to check that whether they are anagrams
1:32:56
of each other. So this would eliminate like all the bad examples. Okay. Now let's see that what is going to be the
1:33:02
logic for the given subsequent S and D. Let's say that the current S has the
1:33:07
word cart and the current T has the word uh red RATC. Okay, they are the anagrams
1:33:13
of each other. Now we already know the pre-existing condition on what defines
1:33:19
an anagram that the frequency of any particular character present at S and D
1:33:26
are going to be same in no matter what. So this fact we are going to use to
1:33:32
basically come up with a clever solution. Now first approach is that we actually use a hashmap or second
1:33:39
approach is that we basically use an array. Now why we are able to use an array in this case to solve the problem
1:33:46
because we know for a fact that English language only has 26 character. So we can actually initialize a character an
1:33:53
array with 26 size in it. And based on the index position we would mark like
1:33:59
subsequent um positions within uh the characters. So let's say that if we are
1:34:05
dealing with character A then a has to be present on the first index of our array. Same way B has to be present on
1:34:12
the second index of the array. Okay. Once we have an idea on how we are going
1:34:17
to keep track of the frequency. Now what we need to do is that frequency has to
1:34:22
match both on S and T. So for that what we will do is we will start iterating
1:34:28
over u for s and d at the same time. We know that they are both at the same
1:34:33
length. So we can just use one one for loop or one loop to iterate over them.
1:34:38
For every single character that we find we are going
1:34:46
and for each of them we are going to initialize values with values zero. Okay. And now let's just let me just
1:34:52
arbitrary mark values like C A R and T. So C A R N T these let's assume these
1:34:58
are the values like actual values would be different based on their character positions. I'm just putting it here so
1:35:04
that it would be easier for us to visualize. Okay. Uh so first we have character C at position number S. All we
1:35:12
are doing is that whenever we find a character in S, we are going to increment the counter within the array.
1:35:19
And if we find a character inside the T which means we find like a subsequent reciprocal character. So then we are
1:35:26
going to decrement the counter. Uh and how it is going to work is first we identify character C over here. So we
1:35:31
are going to increment the counter to value number one. So let's just mark this as one. Subsequently at the first
1:35:37
position the value is R. So once again for R we are going to decrease the counter. So this is going to become
1:35:42
minus one. Okay. Now for a once again we are going to increase the counter based
1:35:48
on this s and we are going to decrease the counter because this is also a so that this would become minus one. So one
1:35:54
basically overall this value would become zero after this change. Okay. Now
1:35:59
next we have r. So in this case we are going to increment r. Now notice the value of r is already minus one. So we
1:36:05
will turn it back to zero. And this value is t. So currently t is zero. So this value would become basically minus
1:36:12
one. Okay. Okay. And last one is t. So in this case, notice that t is going to become uh zero. So let's just mark t as
1:36:18
zero. And this value is c. So we will have to reduce the value of c. So if we reduce the value of c, basically this is
1:36:26
going to become zero zero as well. And now notice that after iterating over all
1:36:31
of this, we found out that every single character that was present inside the s is also present inside the d. And what
1:36:39
is the way for us to check it? we simply iterate over the this given array once. If we find for any particular character
1:36:46
that there exists some value that is other than zero then we can simply return false saying that they are not
1:36:51
anagrams of each other. And let's take that as that example as well that let's say over here inside the input let's say
1:36:57
that this value is still cart and this value is over here it's let's say R A to
1:37:04
O. Uh so notice in this case this C would have remained one because we had
1:37:11
uh C over here that was not present inside this T and notice that for this character O let's say that this is the
1:37:18
character O this value would have been minus one. So overall we would have like
1:37:23
more than one values that does not contain value zero and we can explicitly say that because this is the case we can
1:37:29
simply say that they are not anagrams of each other. So this is a very fast and beautiful approach. Now let's try to
1:37:35
calculate time and space complexity. In this case, time complexity is going to be big of n where n is the total number
1:37:41
of characters present inside the uh s or t. And in terms of space complexity,
1:37:46
well, this is still going to be constant space complexity because even though we are initializing an array, the maximum
1:37:52
length of that array is going to be 26 characters only, which is a constant space. It is not continuously growing
1:37:58
and it doesn't change with the given original input. So that's why this is a beautiful time and space complexity. And
1:38:04
now let's quickly see the coding solution for this one. So the coding solution is quite straightforward. First
1:38:10
we will check that whether the length of s and t are equal or not. If they're not equal, we can simply return false. If
1:38:16
that is not the case, we will initialize our array called character counts. That is going to be of size 26. Then we will
1:38:23
increment the count for every single character that is present in S and decrement the count for every single
1:38:29
character that is present in T. And we can just simply update the character counts array that we have just
1:38:35
initialized. And after that all we need to do is to check that if in the
1:38:40
character count array are there any other values that are not zero. The moment we find a nonzero value we can
1:38:46
simply return false saying that S and T are not anagrams of each other. If we do find all the values are zero and get out
1:38:53
of this loop which means they are anagrams of each other and we can simply return true. So let's try to run this
1:38:58
code. Seems like our solution is working.
1:39:04
Let's submit this code. And the code beats nearly 45% of all the
1:39:10
resolutions which is pretty good. If we see memory it beats nearly 80% of all
1:39:15
these resolutions which is awesome. So once again the coding solution is present on our GitHub repository. Feel
1:39:22
free to go and check it out from there. Thank you.
1:39:31
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do group anagrams lead code
1:39:37
problem. And this problem has been really popular at some of the companies where I want to get a job. There are
1:39:43
companies like Amazon, Microsoft, Facebook, Apple, Google, Affirm, Snapchat, Goldman Sachs, Uber,
1:39:49
Bloomberg, Netflix, Instacart, Bite Dance and Twitter have already asked this question. So that's why I'm paying
1:39:56
my utmost attention. I hope you also enjoy the video. So this is a lead code medium problem
1:40:02
and basically we are given an array of different strings and we need to group the anagrams together. Now we can return
1:40:08
the answer in any order. So which is good for us and we are also given the definition that what is an anagram?
1:40:13
Anagram is a word or a phrase that is formed by rearranging the letters. Uh and then it turns out to be a different
1:40:19
word. So if we take an example suppose we are given a word like bat. Then we can say that these all are actually
1:40:26
anagrams of this original word bat because the b a and t they are all occurring in all of them in the same
1:40:32
number of occurrence that it it is present in this bat. So now after understanding that what an anagram is
1:40:37
let's try to see some examples to understand that what this question is asking us to do and what is the expected
1:40:42
answer we need to return. If we take this first example essentially we are given s is equal to area of string that
1:40:49
looks like this. Now over here I have clearly marked all the groups that can be potentially done in separate colors
1:40:54
so you can clearly look at them. Uh but the thing is let's try to understand. So first of all we are given this word e a
1:41:01
t eat. If we see the what are the number of occurrences of characters there are characters E A and T occurring one times
1:41:07
each. Now same thing happens for this word T E A T and for this word A T E
1:41:13
which means we can conclude that all of these three words are actually anagrams of each other and we can group them
1:41:19
together in one single group. So that we are now we are done with all of these three elements. Now next item we see
1:41:26
there are two words tan and net again t a n this all all three of them are
1:41:32
occurring once these three characters for both of these values. So we can also group them together. Now for this b a t
1:41:38
back we actually don't have any other value that we can consider it as an anagram. to this uh particular string
1:41:44
will be a group of itself which means in this case we can answer we can return an answer that looks like this
1:41:52
and we can return this as an answer. So clearly you would find that this answer
1:41:58
actually the sequencing is done slightly bit different than what is the answer
1:42:03
given in this output and the reason for doing that is that I wanted to show you that we can return answer in any order.
1:42:10
So that is the important part over here that that is specified in the question that we can return the answer in any order. So that's why I ordered them
1:42:17
differently but as long as the groups are correct we are good to go. One better way to solve this problem is
1:42:23
actually by using sorting. And how we are going to use the sorting is that we are actually going to create another array for every single entry that is
1:42:30
present inside this original S. And for all the elements that are present over here, we are going to actually sort them
1:42:36
in alphabetical order. And then all we have to do is just we will have to iterate over this newly created array
1:42:41
once and we only need to find that what are all the similar pairs or all the similar values and then we can simply
1:42:47
return them as answer and that that makes our life much more easier. Let me quickly show you what I'm suggesting. So
1:42:53
based on this array, we will actually create actually create a sorted array and the sorted array is going to look something like this.
1:43:00
So now we have created our sorted array and which we have derived from this original s. Now all we will have to do
1:43:06
is we pick up any word or any uh string. Then we just have to compare with all
1:43:11
the other strings and find that which strings contains the same value. Whichever string contains the same
1:43:16
value, we will take their values from the original string because we know that they're index values and then we can
1:43:22
group them together. So the idea is first of all we'll take this uh string a e then we find that okay this and this
1:43:27
both of them. So the strings located at position 0 1 and three they are all part of this original uh string that should
1:43:34
be in the single group. So we will group them together. So in the answer we will mention eat t and 8 as one group. Then
1:43:43
again we will repeat the same process. So we find this ant and and end. So again we will group the whatever values
1:43:49
located at this string at this index two and four and for we find the values 10
1:43:55
and net and in the end we will return this bat because it's the single one. So
1:44:00
this solution would work fine. We will get our desired answer. If you see the time complexity in this case, the time complexity is actually going to be bigo
1:44:06
of n log n just to create this uh original sorted string multiply by k and
1:44:13
this k is actually the biggest length of the string that we will have to compare and uh this would be the final time
1:44:19
complexity. So this is much bigger improvement than our brute force approach which was giving us the big of n cq time complexity. Now let's see that
1:44:26
can we improve any further in this one as well.
1:44:33
Okay, before we come to the optimal solution, we will have to ask a very important question that how do we determine that any two words are anagram
1:44:39
of each other or not. Suppose we are given two words like A B C and CBA. We
1:44:44
can clearly see that they are actually anagrams of each other. But how can we explicitly define that yeah they are truly anagrams of each other. Well, we
1:44:51
can define that based on the number of character repetition in each one of them. that any character that is present
1:44:57
in this ABC it is also present in the CBA in the exact same number of occurrences that both in in both the
1:45:05
words. So in other words uh A B and C is present exactly once in this particular
1:45:11
word and it is also exactly once present in this particular word though the arrangement is different and that makes them anagram of each other. Now you'll
1:45:18
ask that why am I dragging so long on this pretty trivial question that we already know the answer to. Well, we are
1:45:23
actually going to use it to our advantage. And uh the good thing for us is that English language only has 26
1:45:30
characters. So because English language has the 26 characters, we are actually going to use it to to our advantage. We
1:45:36
are actually going to create an array of all the values that are initially located as zero and that is going to be
1:45:43
of size 26. Now any character that we identify in any single string we are actually going to add it to our array
1:45:49
and we are going to increase the value of that particular character sequence and then whatever the answer of that car
1:45:55
is that array is we are going to put it in a string and then we are going to use it as a key for our hashing hashmap uh
1:46:04
hashmap and then we are going to do some interesting things. So let's let me quickly show you that what is the full
1:46:10
plan. Suppose over here we are given an array that looks like this. Right? Now we need to we have this given word ABC.
1:46:16
So what we are going to do is initially all of these values they are defined as zero by default. But now we are given
1:46:22
this ABC. So first of all we take this A we increase its value to one. Again we get this B we increase its value to one.
1:46:29
Again we get the C we increase its value to one. Now all the other values they are zero so far. So for this particular
1:46:35
character we can actually create a string based on this given array of 26
1:46:40
words. So string will be maximum of size 26 which means it is a defined finite
1:46:45
number we which means we can create that we will get a string that looks like this 11 1 and then uh remaining 23 zeros
1:46:52
again we are given this word ca right so again what we are going to do first of
1:46:57
all we identify this character C so we are going to mark its value as uh initially this was zero so we are going
1:47:03
to mark it to one again this b again we will mark it to one and again this a we will mark it to one all the other values
1:47:09
would be zero So even for this one the string that we are going to generate is going to look like this 11 1 and 0 0 0.
1:47:16
Now the idea is that we will create a hashmap. Now inside this hashmap as a
1:47:21
key part we are actually going to keep track of whatever the string that we are building. So let's just name this as
1:47:28
string builder that we are building a new string that would be our key. Now in both the cases notice that for this ABC
1:47:34
and for the CBA the string value is actually going to be the same that it would be 11 1 followed by 23 zeros in
1:47:41
both the cases which means that it they both have actually same key value which means that over here okay this is 11 1 0
1:47:47
0 23 times but in both the cases as the value we are actually going to keep track of a list and inside this list we
1:47:55
are going to store original words that were presented as an input for this
1:48:01
original array string that we built. So over here first of all we will have an entry that looks like a b c and then we
1:48:07
will have an entry that looks like cba. Now we already have both the values that
1:48:14
are that is part of the same group or they are which is an anagram of each other would be in the list value which
1:48:22
means that that makes our life much more easier that in the end all we need to do is just we need to return this whatever
1:48:28
value we have stored in the list. Let's do this with one of the example that we have been following so far. So I'm not
1:48:34
going to show you the whole ordeal with the array because that is too time consuming. We are I'm just going to show
1:48:39
you that what would happen inside the hash set uh hashmap. So this is our hashmap. Now as a key we are going to
1:48:46
have some string value. So first of all we get this value eat. So suppose for this value number eight we get the
1:48:52
string that looks like looks something like this right? Whatever the value is. Now the same value is going to look for
1:48:58
this T and for this 8 which means that these values eat then T and 8 would be a
1:49:06
part of the same value group inside this hashmap for the same key. Again same
1:49:13
thing will happen for this tan and net. So even again for this tan and net suppose we get some value that string
1:49:19
that looks like this right I'm just random drawing bunch of gibberish but you you get the idea and we will add an
1:49:25
entry for tan and net because they both will have the same number of occurrences of characters and in the end for bat we
1:49:32
won't have any entry so we will have a new entry over here and where we will add the value bat now in the end all we
1:49:38
have to do is just iterate over all the values that are present inside this hashmap and return it as our answer and
1:49:44
this would be the optimal solution we are going to use. If we see the time and space complexity for this one, the time
1:49:49
complexity is actually going to be big of n times whatever the maximum length of k is. In terms of space complexity,
1:49:56
we are actually creating an additional hashmap. So that's why that is going to take some additional space. But this is also going to be big of n * k where k is
1:50:03
k is the longest length of any given string and n is the number of string that are present inside the given input.
1:50:13
So first of all we are going to check an edge case that if the given string is empty we are going to return an empty array list immediately. Okay if that is
1:50:21
not the case we are going to initialize our hashmap and we are going to take string as key and uh list as value.
1:50:28
Also we are going to initialize our array of size 26 and we are going to name it as count. Once that is done we
1:50:34
are going to run a for loop across the given input string. So first of all we are going to initialize our array with
1:50:40
value zero. After doing that we are going to iterate over this given string s and we are going to add all the
1:50:46
characters inside this given array by adding their value from 0 to one.
1:50:52
After doing that we are going to initialize a string builder to store the string value that we have retrived
1:50:57
inside this character array. Now we are going to run across the count array and we are going to add all the
1:51:03
values store string builder. Also at the same time we are also going to add a hash before all the elements inside this
1:51:09
given count array. And that is something per language trick that changes for Python. You won't have to do it.
1:51:17
Once this is done, we are going to assign this new string that we created as a key for our hashmap.
1:51:24
We are going to check that if this entry for this given key already exists inside the hashmap. If it does, we are simply
1:51:30
going to add whatever the string s that we are iterating over. And if the entry does not exist, we will create one value
1:51:37
inside the hashmap. And then we will add this uh value s for this given key.
1:51:44
And we are done for this for loop. Now all we will have to do is return all the values from this answer map and return
1:51:51
it in the manner that is asked inside this given question. So we will have to return a list of uh lists.
1:51:58
Let's try to run this code. Okay, seems like our solution is working
1:52:03
as expected. Let's try to submit this code and our code works as expected. I'll be
1:52:09
posting the solution in the comments so you can check it out from there.
1:52:20
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do product of an array except
1:52:27
self lead code problem. If we see some of the companies where I want to get a job who have already asked this question, there are companies like
1:52:33
Amazon, Microsoft, Facebook, Apple, Uber, Bloomberg, Lyft, Google, Fullman's
1:52:38
X, IBM, Twitter, Tik Tok and LinkedIn. So that's why I'm paying my utmost attention. I hope you also enjoy the
1:52:44
video. This is a lead code medium problem and also very well-like problems on lead
1:52:49
code. Basically we are given an integer array called nums and we need to return a new array called answer array such
1:52:56
that every single value of that particular index position inside this answer array is actually equal to the
1:53:02
product of all the other values that are present inside this given nums array except that particular e element. So
1:53:09
suppose we are given an input array that looks like this. This case we will have to create an answer array for the answer
1:53:16
and that would be of the same size of whatever this input array we are given. Now in this answer array suppose we want
1:53:21
to enter the value at this uh second position corresponding to the second index value. What we are going to do is
1:53:27
we are actually going to take the product of this value number one 3 and four and whatever the product of these
1:53:33
three values are we will actually put it as the answer for this value. Same thing we are going to do for this uh next
1:53:38
value where we are going to take products of these two elements and this element but we won't take the product of this element from this original given
1:53:44
input array and whatever the answer is we will actually put it over here inside the answer array. uh in order to enter
1:53:50
this first element we will actually have to do the product of these three values. So in the product of these three values is going to be 24. Uh now for the second
1:53:57
element we will have to do the product of this first element and this last two elements. So that is going to be 12. Uh
1:54:03
for this third and fourth element we will again repeat the same process and we will get subsequent values like 8 and
1:54:08
six by doing the corresponding products and at the end we will have to return this as the answer array. And uh
1:54:16
basically this is what the problem is asking us to do. Uh even the name is also self-explanatory that we need to
1:54:21
return the product of an array except self. But we are given a very specific declaration over here that we need to
1:54:27
use it in big of end time without using the division operator. And why it is
1:54:32
asking us to use uh solve this problem without using division operator because if we were allowed to use division
1:54:38
operator. Suppose we are given an input. We can just do the product of all of these value and we will get an answer
1:54:44
called 24. And then all we have to do is for this answer array we will take this value 24 and then we will iterate over
1:54:51
this input array and start dividing it with this 24. So even in the answer we will get if we divide 24 by 1 we will
1:54:57
get the value as 24. If we divide 24 by 2 we will get value 12. If we divide 24 by 3, we'll get value 8. So so on and so
1:55:04
forth. So it would become very easy for us to solve this problem. So that is why they are explicitly asking us that we
1:55:10
should not be using the division operator. Now the most basic brute force way to
1:55:15
solve this problem is actually we take any single value and then we iterate over all the remaining values and do its
1:55:20
product and put it in the answer array. So we will create an answer array that looks like this. We will first take this
1:55:26
value. So we will iterate over this given nums array and for all these three values we will do its product and we
1:55:31
will get the value is 24. Now again we will repeat the same process but this time we will be iterating over the second element. So because we are
1:55:38
iterating over the second element we will take this first value and we will take these two values and we will do that sum. So we will get value number 12
1:55:45
and again we will repeat the same process. So essentially this is bound to give us the correct answer and we would
1:55:50
get it in this case. But thing is this is this would not be the correct way. Why? Because if we see the time complexity in this case, the time
1:55:56
complexity is actually going to be big of n². Why n square? Because we will have to iterate over this array. For
1:56:02
every single character, we will have to iterate once. And even for any particular character, we will have to iterate over all of the values again
1:56:09
just to find their product number and that takes n square time and we are explicitly told that we will have to
1:56:15
solve this problem and we go of n time. So let's see that what would be the way to achieve that.
1:56:20
Okay. So now for the better approach we will actually have to put down one intuition to use and the intuition is
1:56:26
suppose this is the element we want to get the product for in the answer array. So the idea is that we are actually
1:56:31
going to take the product value of first two elements and we will take the product of this last element. Again if
1:56:37
we take this portion this value number two we will take the product of all the elements that are present on the left of
1:56:43
this value number two and we will take the product of all the elements that are present on the right of this product number this value number two. So that is
1:56:50
the idea that for every single location we will have to take product of all the values that are behind or pre to that
1:56:56
particular level so we can call it as prefix and all the values that come after that value and we can call it
1:57:02
postfix. So now the idea becomes quite simple. What we are going to do is we are going to have two uh arrays called
1:57:09
prefix and postfix and we are going to iterate over this nums array once and
1:57:14
for every single position we are actually going to keep track of all the values that come before it and after it
1:57:20
and we are going to put down their error values uh like their product values and at the end we will just do a
1:57:26
multiplication between this pre and post arrays and then we will we should get our answer. So let's see that in action
1:57:33
and also one more thing that because for this particular element that are at the edges uh so for this value number four
1:57:40
there is nothing on the right side. So like we can't do anything but uh for the simplicity purposes we'll consider that
1:57:46
anything on the right side is actually one because anything multiplied by one remains the same. And same thing we are
1:57:51
going to do for this left edge as well. That because for this value number one there is nothing in the prefix. So again
1:57:57
by default we will treat this as value number one as well. So that will help us in uh doing some counting right. So
1:58:04
let's see that in action. So first of all for this value number one we will we are calculating the prefix values. So
1:58:10
this one actually has nothing on the left but it only has one. So we'll do 1 * 1 and we will get the answer as one.
1:58:16
Now for this value number two actually all we need to do is whatever the left element is we we just need to do the
1:58:23
product of all of them. So the left element in this case is only one and we will just put it over here as well. Now
1:58:29
in this case the value number three we will have to do product of all these elements. So one way to do it is to do
1:58:36
this like 1 * 2. So do the product of all the these two elements. But that is
1:58:41
actually timeconuming. One better way to do it is that uh if we take this particular element value number two this
1:58:47
already contains the product of all the values that are be present before that. So why are we doing the effort of doing
1:58:54
the product of this value number one and two that is just costing us additional resources. The better approach is that
1:58:59
we for this value number three uh we are over at this position. All we have to do
1:59:05
is we just take whatever the value we have stored over here which is the prefix of all the values before this
1:59:11
value number two multiply by whatever this value is present and that would be the prefix sum for this value number
1:59:17
three. So what we are going to do in this case is we will take this value number two. So we will take this value
1:59:22
number two and we will take this value number one from here from the prefix array that we have already calculated
1:59:29
and we will do 2 * 1 in this case we will get value as two. So we will add two over here and again for this value
1:59:35
number four again we are going to repeat the same process. So now this time we are going to take the value before that
1:59:41
is three. So we'll take three and we will multiply it by whatever value we have already found in this prefix array
1:59:47
which is 2. So 3 * 2 is actually going to be six. So now we are done with this
1:59:52
prefix array. Again we are going to repeat the same thing for the prop postfix array. So this is the edge
1:59:58
value. So we can simply do four * 1. So we'll add the value four directly over here. Now this is value number three.
2:00:04
For this value number three, all we will have to do is just take product of this value. So this is already four. So we will again add four over here. Now for
2:00:11
this value number two all we have to do is we will take the value this whatever value that is present over here three
2:00:17
multiply by whatever value we have already calculated in the postfix over here which is 12. So we will have a
2:00:22
value called 12 over here for this uh element number two. And now again for this element number one we are going to
2:00:28
repeat the same process. We will take this two and multiply it by whatever value we have calculated inside our postfix array. And this is going to be 2
2:00:36
* 12. Okay. Now we are done with both of our arrays. Now the task is actually quite simple. Now we will create our
2:00:42
answer array and we are going to simply do the multiplication of every single one of these values. So this becomes 24
2:00:49
* 1 24. This becomes 12. This becomes 8 and this becomes oh I made a mistake over here. This has
2:00:57
to be 1 not four because we are actually doing the multiplication of all the elements that are present on the right
2:01:03
side of this value. So this would become six. And this is the solution that we are we are going to do. Uh this solution
2:01:10
actually works perfectly fine. There are no issues with that. If you see the time and space complexity in this case, the time complexity is actually going to be
2:01:16
big of uh 3 * n. Why 3 * n? Because we will have to iterate over this n to
2:01:22
first of all create this prefix array. Then we we have to iterate over n times to create this postfix array. And then
2:01:28
again we will have to iterate over both of them to create this answer array. So we are doing like three times n work.
2:01:34
But in general we can write this as big of n and in terms of space complexity uh
2:01:39
we are actually creating couple of arrays. So we also have to do big of n as space complexity. So the idea is can
2:01:45
we do something better and the answer is yes. There is one way to actually do this both prefix and postfix array in a
2:01:52
single array and that to inside the answer array that we are planning to create.
2:02:00
Okay. So let's keep the same example and we want to find the optimal solution for this one. Well, the idea is that rather
2:02:06
than doing two separate prefix and postfix arrays, we are actually going to create an answer array and we are going
2:02:12
to add all the values. And now we are going to do prefix and postfix multiplication inside the same answer array. And let me quickly show you how.
2:02:19
First of all, we are going to use couple of variables called prefix and postfix. So let me add their values and by
2:02:25
default they are going to have value as one. Now what we are going to do is first of all we are going to iterate over this given input uh nums and we are
2:02:33
going to calculate the prefix for every single element inside this answer array and we are also going to update the
2:02:38
value inside this pre function uh or prevariable and then again we will iterate in the reverse order and we will
2:02:45
keep on updating the postfix values inside the answer and by the time we are done uh our answer array should have
2:02:50
been completely filled out. Let me quickly show you that in the action. So first of all uh for this value number
2:02:56
one uh this is actually the prefix of uh every every value that is present behind
2:03:02
this one and uh the multiplication of all of those values. So because there is nothing over here. We can consider this
2:03:07
to be one by default. So I'll not write it over here. I'll just write over here that for this first element inside this
2:03:13
answer array the nums actually does not have anything on the left side left side. So we can consider this to be one.
2:03:20
Now we are going to uh we are at this second position. For the second position what we are going to do is we are going
2:03:25
to take the multiplication of whatever the value we have on the left side right. So even on the left side we only
2:03:30
have value one and even the prefix value is also one so far by default. So we are going to add one over here again. Now we
2:03:37
are at this value number two or three. So for this value number three what we are going to do is we are actually going to take the the value that is before
2:03:44
that which is two and we are going to multiply it with whatever the prevariable we have. So we were also
2:03:49
doing the same thing for this value number two as well. But because both the values are one, we were not getting any other result. But in this case, we will
2:03:56
actually get a result of two. And because we are getting a result of two, the result of pre is also updated also
2:04:02
being updated to value number two. Um because it will help us to know further down for the next elements that what is
2:04:08
the value of prefix. Now we are at this value number four. So again we are going to repeat the same process. We will take this value number three and we will take
2:04:15
whatever the value of this prefix we have which is 2. So 3 * 2 uh the value six. So we'll add value six over here.
2:04:21
Okay. And now we are done filling up this prefix portion. And we have taken the prefix of every single element
2:04:27
inside this answer array. Now we are going to do the reverse order. Now inside the reverse order again for this
2:04:34
value number four. Actually uh there is nothing on the right side of this value number four which means there is nothing
2:04:39
on the postfix. So we can consider it as one. Now because this is already one. What we are going to do is whatever
2:04:45
value we have calculated so far we are going to multiply it. So if we multiply six by one the answer we get is six.
2:04:51
Okay. So so far uh for this value number four the answer is six. Now we are at this value number three. For this value
2:04:57
number three what we are going to do is we'll have to calculate everything on the postfix side. So this value is four. So we are take going to take value four
2:05:04
multiply by whatever value of this postfix variable we have which is 1. So 4 * 1 becomes 1. So now we have the
2:05:11
value as four for this postfix. So we are going to update the value of the postfix to be four and we are also going
2:05:17
to multiply this four with whatever the value we already calculated for this value number three which is two. So 4 *
2:05:23
2 is going to be 8 and this is going to be answer for this value number three that this is the product of all the
2:05:29
numbers for this value number three except itself. Now we are at this value number two. For value number two we are
2:05:34
going to take value number three multiply it by whatever the post variable we have. Post variable is
2:05:39
actually four. So 3 * 4 is actually 12. So we are going to update that value over here first of all. So now we have
2:05:46
the value 12 over here and we will have to take this 12 and multiply it with
2:05:51
whatever value we have already stored over here which is 1. So 1 * 12 is also 12. And now again we are at this last
2:05:57
position. So again for the last position we are going to repeat the same process. We will take whatever the value that is
2:06:04
after this value number one which is two. So we'll take this two. we will multiply it with whatever value we have stored inside this post variable which
2:06:11
is again 12. So 2 * 12 and we this becomes actually 24. So we will do 24
2:06:17
and we will take 24 multiply by whatever value we have already stored inside this answer array which is 1. So 24 * 1
2:06:23
becomes 24 and this is the answer. And if you look closely this actually
2:06:30
becomes the complete answer that we are looking for. And we have actually done everything in place without using any
2:06:35
additional data structure or any additional array and we don't have to use basically any extra space. So this
2:06:42
is the best way to approach this problem and this is the solution that any interviewer would want to see. If we see
2:06:49
the time complexity in this case, the time complexity is actually going to be big of 2 n. Why 2n? Because first of all
2:06:54
we are iterating over from uh left to right calculating this prevariable and then we are iterating on the reverse
2:07:00
order calculating this post variable and updating the values. But still which is good if we see the space complexity in
2:07:06
this case. Oh well space complexity is actually constant because we are not using any additional space for this
2:07:11
answer array. We are given inside this uh question statement that we have to create a new array. So that we are
2:07:17
anyways going to create but apart from that we are only using couple of variables to store some data and uh
2:07:23
that's why this is a very good approach. Now let's move on to coding.
2:07:30
First of all we are going to create a new array called result. And by default we are going to set all the values as
2:07:36
one. We are going to initialize the two variable called prefix and postfix. And
2:07:41
we are going to assign the value as one for both of them. Okay. Okay, now we are going to run our first for loop to
2:07:46
iterate from left to right and we are going to update the value of prefix inside our answer uh array.
2:07:53
So first of all we are going to update the value inside our result array and then we are going to update the
2:07:59
value of our prefix variable. So after this loop ends basically we
2:08:04
should have uh prefix values filled out for every single position inside our result array. Now we are going to run
2:08:09
another loop and we are going to come in the reverse order and first of all we are going to update the value inside the
2:08:16
result array. So any single value inside the result is actually going to be multiplication of whatever the value we
2:08:22
already had multiply by postfix variable also have
2:08:28
to update the value of postfix variable. We are good to go. Oh actually I made a mistake. This should be pre only not
2:08:34
prefix. Okay. And after this second loop ends,
2:08:42
essentially our result error should have been populated. So we can simply return that.
2:08:48
Let's try to run this code. Okay, seems like our solution is working as expected. Let's submit this code.
2:08:57
And our code runs pretty efficiently compared to lot of other solutions. So that's why this is really good approach.
2:09:02
I will be posting the solution in the comments. So you can check it out from there. Thank you.
2:09:13
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do top K frequent elements
2:09:20
lead code problem. And if we see some of the companies where I want to get a job who have already asked this question. There are companies like Facebook,
2:09:25
Amazon, Microsoft, Google, Uber, Apple, Bloomberg, Snapchat, Twitter, Tesla,
2:09:31
Netflix, Bite Dance, LinkedIn, eBay and Tik Tok. So that's why I'm paying my utmost attention. I hope you also enjoy
2:09:37
the video. This is a lead code medium problem and also very well-like problem on lead
2:09:43
code. Basically, we are given an integer array called nums and we are also given a separate integer called k. Now we need
2:09:50
to return the k most frequent occurring elements from this nums array and we are also told that we can return the answer
2:09:56
in any order. So first let's try to understand this problem with this example. I have actually drawn it much
2:10:01
bigger over here. So this is the array nums that we are given and we are given k is equal to two which means we need to
2:10:07
return top two elements that are present inside this given nums array right. So
2:10:12
if we see in this case well over here this one is actually present three times
2:10:17
this two is actually present two times this three is actually present one time. Now if we see we are given that k is
2:10:24
equal to two which means we need to return top two elements and clearly we can see that the top two elements in
2:10:29
this case is this one and two. So we can return the answer to be uh 1 and two or
2:10:35
we can also return two and one because remember we are told that we can return answer in any case and this is the
2:10:40
answer we need to return. So let's try to see that what is going to be the approach to solve this problem. Now let
2:10:45
me make one clarification. There are actually two different approaches to solve this problem. One approach or the
2:10:50
first approach I'm going to show you in this video is actually sufficient for your interview. Any interview would be
2:10:56
more more than satisfied with that approach. But thing is the second approach I have is actually the golden
2:11:01
key approach for any like top k element problems right any heap problems you can
2:11:07
use the second approach and uh I'm actually planning to make a separate video on that depending on whether you
2:11:13
want to learn it or not so let me know in the comments that whether you want to learn the second approach if you do I'll
2:11:19
make a separate video we are actually going to use the combination of a hashmap and a heap in
2:11:26
order to achieve the top k element ments. So I have created a custom example over here and I have given the
2:11:31
value of K is equal to three. Now remember whenever we need to define that we need to return top K elements or top
2:11:38
three elements and in in this case how can we define that? Well we first of all need to iterate over this given given
2:11:45
entire array. We need to find that how many times any single character is occurring and depending on that answer
2:11:52
we will have to iterate over that uh whatever the list we create where we have the number of occurrences for each
2:11:59
character and then we can conclude this answer. So one thing is clear that we need some way to store the information
2:12:05
that how many times any particular individual character occurs. For that we
2:12:10
are actually going to use the hashmap. in the hashmap as the key we are going to denote the distinct value of this
2:12:17
given array and as its value we are going to note the occurrence of that particular character. So first let me
2:12:23
quickly create a hashmap for this given input which contains the distinct values
2:12:28
and their occurrences. So based on this given input this is the hashmap we can create. Now we need to select k is equal
2:12:35
to three which means we need to provide top three elements. Now one approach to find the top three elements is that all
2:12:41
the distinct values we have in this hashmap. If we just simply create a sorted array and in the sorted array we
2:12:48
sort the arrays based on uh the descending values which means the most occurring value to be first and then we
2:12:54
put down all the remaining values. We can actually generate a sorted array that looks like this. And now for this
2:13:00
particular sorted array we can simply return the top three elements. So we can return the answer to be like four 3 and
2:13:07
five easily and this is the solution that would give us the correct answer. But thing is you would quickly and ask
2:13:13
me that why did I mention priority key over here because over here what I'm doing is I'm taking this hashmap and I'm
2:13:19
actually just sorting it and we are able to generate the array. Well first of in order to understand that first of all
2:13:25
let's understand the time complexity of this approach. The time complexity of this approach is first we need to iterate over the given entire input. For
2:13:32
that it takes big go of n time to generate this hashmap. After generating this hashmap we will have to create the
2:13:38
sorted array that takes n login time to generate that answer and this n log n is
2:13:44
going to be the ultimate time complexity. So the thing is this you would say hey n login n sounds
2:13:49
reasonable. The thing is uh from n log n suppose we have like 1 million uh
2:13:56
distinct characters or 1 million characters and we are given k is equal to 3 which means that we would have done
2:14:01
like 1 million * log 1 million work. Meanwhile the value of k in practice is
2:14:07
supposed to be much smaller than whatever the input size is going to be. So the other approach is that if we
2:14:14
create a priority Q and remember the concept of a priority Q is that inside
2:14:19
the priority Q basically we add the values and we remove the values just
2:14:24
like any cues but thing is the values that we are entering they have some meaning behind them and depending on
2:14:30
their valuation we actually store the value. So whenever over here suppose this is the priority Q and I have
2:14:36
provided different uh weight to those elements. If I want to create or if I
2:14:41
want to enter an element that is an higher weight then I would get rid of only the lower weight elements and add
2:14:48
those over here. Uh I would not be repeating everything. So based on that concept what I'm suggesting is that
2:14:54
rather than sorting this array we get rid of it. Okay. So let me clean this up a bit. And over here from this actual
2:15:01
hashmap that we have created we actually create a priority Q and this priority Q
2:15:08
is going to be of whatever the size we are given of the K value. Okay. So K in this case is three. So we are going to
2:15:14
only have three values in our priority Q. Now for our priority Q first of all we are going to check that okay we only
2:15:20
enter the values based on the number of occurrences they have and we only keep the higher number of occurrences. So
2:15:27
first we add the value number one over here because we don't have anything. Now we add value number two over here
2:15:32
because we still have room and two has two occurrences. Then we add value number three because three has three occurrences. And remember we are using
2:15:38
the occurrence to add the value not the actual distinct value. Right? This is the key part. Okay? Now we have this
2:15:44
value number four. Four actually has four occurrences. Right? And so far if you remember this one had one
2:15:50
recurrence, this two had two and this three had three occurrences. Now we have a value that is four that has actually
2:15:56
four occurrences which means it is greater occurrences. So we are able to insert that value inside our priority Q
2:16:02
and uh in that case we are actually going to get rid of the smallest value. So smallest value in this case was one.
2:16:09
Now we are not going to add four over here but we are also going to maintain the uh ascending order in terms of the
2:16:16
values that we are being added. So we'll just shift these values. Okay. So two will come over here, three will come
2:16:21
over here and four will come over here and then we will have those subsequent values. Now uh after adding this we
2:16:27
still have value number five that we need to add. So five occurs three times. So five occurs three times. Currently we
2:16:32
have two occurring two times, three occurring three times and four occurring four times. Now five occurs three times. So five is able to enter over here
2:16:39
because it occurs more times than this two. And we can actually put five over here uh because it is also occurring
2:16:45
three times and this three is also occurring three times. So we are good up until this point. After that all we will have to do is just convert this uh
2:16:51
result into an array. So for that particular array we are actually going to store the results and uh remember we
2:16:58
can return result in any manner. So we can return like 5 3 4 or we can also return like 3 4 5 or whatever result we
2:17:05
want to return we can return and this is going to be the solution. If we see time complexity in this case the time
2:17:11
complexity is actually going to be a bigger improvement than our sorted array approach. Why? Because okay over here
2:17:16
this takes big of n time to generate this hashmap. That process remains same. But now from generating this hashmap to
2:17:22
this priority q it takes n log k times because we are only maintaining k
2:17:28
elements. This is the important part and this is what your interviewer is going to focus on. So in this case the time
2:17:34
complexity is actually going to be big of n log k which is good. And in terms
2:17:40
of space complexity well you must have guessed it correctly. it's big of n because we are using couple of additional data structures. We are using
2:17:46
a hashme and we are also using a priority q and this is a very good time and space complexity and uh that's that
2:17:52
is basically the ideal approach. Now let's move on to the coding.
2:17:59
First of all we are going to take care of an edge case that if the given k is equal to whatever the length of this nums is we can simply return nums. That
2:18:06
is not the case. We are going to initialize our hashmap. Now we are going to iterate over all the elements that
2:18:12
are present inside this given nums. So we are going to run a for loop and after the for loop ends we are basically going
2:18:17
to populate the values inside our count uh hashmap that we have just created. Now we are going to initialize our
2:18:24
priority cube and inside our priority Q we are going to assign the method of
2:18:29
insertion. So we are inserting based on the number of occurrences based on this
2:18:35
count hashmap. So let's uh put the condition for that. So now we have now
2:18:40
everything is set up. Now all we have to do is just iterate over all the keys that are present inside this count
2:18:46
hashmap that we have created. And for every single key basically we are going to add that value to our heap priority
2:18:52
Q. And whenever the priority Q gets full to the size of this K, we are basically
2:18:58
going to pop the element. And the element that will get popped is going to be the least occurring element. So we
2:19:04
are only keeper keeping higher occurring elements inside our heap.
2:19:09
And now we check that if the heap size becomes greater than k we remove the value from heap. That's it. So now all
2:19:17
we have to do is just simply initialize a new array variable called answer and uh we are going to populate this answer
2:19:24
array. So we will run a for loop for k times and we will keep on pulling the values from our heap. Then we can simply
2:19:32
return the answer. and let's try to run the code. Okay, seems like our solution is working as expected. Let's submit
2:19:38
this code. And our code runs pretty efficiently. And I'll be posting this uh solution in the comments so you can
2:19:43
check it out from there. Thank you.
2:19:53
So we are going to solve a very interesting lead code problem today called Roman to integer. And if we see some of the popular companies who have
2:20:00
already asked this question, there are companies like Amazon, Adobe, Apple, Google, Microsoft, Bloomberg, Facebook,
2:20:05
Uber, Tik Tok, LinkedIn and Goldman Sachs X. So that's why I'm paying my most attention. I hope you also enjoy
2:20:11
the video. So this is a lead code easy problem and
2:20:17
also very valid problem. If we understand the problem statement, it's quite simple. We are given a Roman language number and we need to convert
2:20:24
into a decibel system integer. uh basically that's what it is asking. Suppose we are given a value that looks
2:20:30
like xx then in this case we need to return 20 as the answer because that is what it means in the normal decimal
2:20:37
system. Suppose we are given the value of like uh I I I need to return three as the answer because three is what
2:20:44
represents as I I I in the Roman numericals. Now we are given an very
2:20:49
extensive definition that what every single symbol means in the Roman to its
2:20:55
subsequent value and uh also what are the different symbols and what are the
2:21:01
rules of the Roman language. Now everything these things are pretty easy to comprehend. There is only a little
2:21:08
bit complication when this condition comes in where it says that suppose a
2:21:14
smaller value is placed right before the larger value in that case we need to
2:21:20
make a sub subtraction. Uh so I in this case means one I is a smaller value and
2:21:27
v is a bigger value which means five. Now typically uh if we put any values
2:21:32
like vi what we are going to do is we take the value of v so which is five and we take the value of i which is 1. So 5
2:21:38
+ 1 it is six. So we need to return six as the answer. Uh but the thing is when we are in a condition where the smaller
2:21:45
value comes before the larger value. So say for an example iv this is one of
2:21:51
those scenario. So in this case actually we are going to subtract the value of i
2:21:56
from the larger value and that is how Roman numerical works. So in this case the answer is going to be 5 minus 1. So
2:22:03
four four is what we need to return and there are six such cases where these
2:22:09
numbers can happen. These six cases are so these are six new values that we have
2:22:15
been able to identify based on the rule of a smaller value being placed exactly
2:22:23
before the larger value. Okay. So I have drawn the value
2:22:30
conversion table over here. And now first we will try to understand that how does a numeric system work in the
2:22:35
decimal formula. Suppose we are given a value like 1521. How does this value is
2:22:40
being generated? Well, this is a decimal format. So, in the decimal format, the value is being generated by 10 to the
2:22:47
power of whatever the number of values that are present after it and multiplied
2:22:54
by that particular value. So, let me explain to you that how does this value has been formed. This value has been
2:23:00
formed by doing multiplication of 1 * 10 ^ of 3 because there are three values
2:23:06
present after 1 plus 5 * 10 ^ 2. So if we do sum of these two
2:23:17
we get the answer of 1,000 + 500 + 20 and + 1 and sum of all of
2:23:25
these is actually leads us to the value of 1521 and this is how this value has
2:23:30
been actually broken down. Now in this case if we see the largest value is always presented first then the second
2:23:37
largest value then the third largest value and then the smallest value and this is how the numeric system works.
2:23:43
Same logic applies to the Roman integer for the most of the parts and the logic
2:23:50
is quite simple. So suppose uh in the input we are given the value of how do
2:23:56
we know that what in integer does this value represent? Well the answer is quite simple. All we will have to do is
2:24:02
we will have to see in this table fetch its value and then keep adding the values by itself. So in this case okay
2:24:09
this m is represented by 1,000. Then this d is represented by 500. Then we
2:24:16
have x and x. So we know x means 10 plus another x means 10 and plus i means 1.
2:24:24
So if we do sum of all of these values, the answer we get is 1521. And this is
2:24:29
how this value is being represented. So this seems pretty trivial so far. No
2:24:34
issues with this. And also this is also following the methodology where the largest value is present before the its
2:24:41
small value and before its small value. The problem comes when we have to deal
2:24:46
with uh these six items. So let me also draw these ones as well. Okay. Now
2:24:51
suppose we are given this as an input and these are the values that are anomalies in the Roman integer system.
2:24:58
Uh these are the values that operate in the same way as the decimal system operates. But when we have a smaller
2:25:06
value. So in this case if you see look closely okay m is the greatest value and that is why it is presided at the first
2:25:12
d is second greatest and it is presided at the second value. Well thing is in this case x is actually a smaller value
2:25:19
because x means 10 meanwhile l means 50. So in this case though x is a smaller
2:25:26
value it is it comes before l which means we will have to do a subtraction in this case between these two values
2:25:33
and addition with all the values before that. So in this case let's see what is going to be the answer. So this is going
2:25:39
to be m is going to be 1,000. Then same way this d is going to be 500. That is
2:25:44
okay. But when this x and l comes so basically now what we will have to do is
2:25:50
we will have to do - 10 + 15. So in this case the answer is
2:25:57
going to be 1540 and this is how we need to represent. So the logic is actually
2:26:03
quite simple in this case. If we try to understand what we can simply do is we can simply
2:26:10
create a hashmap with all of these values combined in a single hashmap and
2:26:15
this is going to be the key and uh its subsequent values are going to be the
2:26:20
values. Now every single time whatever the input we are given the logic we are
2:26:26
going to follow is quite easy. Okay. Say for an example this is the input we are given. Now let's see that using these as
2:26:33
the hashmap how we are going to solve this problem. The idea is every single time we will take two values. So in this
2:26:40
case okay these are the two values. We will try to see that whether they are present as keys inside our hashmap or
2:26:46
not. If they're present we directly take its value. If they're not present we break them down and in individually take
2:26:52
their values and do addition and uh keep doing that till we find the answer. So in this case first we will try to see
2:26:58
that okay first two values are MD is MD present as an input? No MD is not present as an input which means we will
2:27:04
have to take M and D separately. So first we will take M. So M's value is 1,000 and plus we will take D. D's value
2:27:12
is 500. So now okay we have taken care of these two values. Now again we will
2:27:17
keep on repeating the same process. So in this case okay we will take these two Excel as one. So is Excel present? Yes,
2:27:23
Excel is present over here and its value is 14. So we can directly add 40 over here in this case for this XL and
2:27:30
directly jump to this I. So okay once this is done now we are again at this
2:27:36
ix. So again we directly try to see that whether ix is present or not. So ix is present. Awesome. Good for us. So in
2:27:43
this case we can directly take 9. And now we do not have any more values to iterate over inside our input. So we can
2:27:50
actually just do sum of all of these values and return as the answer. So in this case the answer is going to be
2:27:55
1549. And this is the whole logic behind our operations. So see if we just create
2:28:02
a hashmap with all the possible values it becomes quite simple for us to solve this problem and that is why this is a
2:28:08
late code easy problem. If we see time complexity in this case the time complexity is actually going to be big
2:28:14
of n that where n is the length of all the values inside the roman inteious.
2:28:19
But the thing is in this case the input we are given a finite number. So because it is a finite number, it is a finite
2:28:25
time to calculate that. So that's why I'm putting the time as constant and even in terms of space complexity. Apart
2:28:32
from using couple of variables, we don't have to use anything. So this is also going to be constant.
2:28:40
First of all, we are going to initialize our static hashmap and assign all of the values we mentioned. After having all
2:28:47
the values, we will start implementing the Roman to integer method. So first we are going to assign some uh variables.
2:28:54
So first variable is sum. The initial value is going to be zero. And we are also going to have an i to iterate over
2:29:00
the given input and initial value is also going to be zero. Now we are going to run a value. First thing we are going
2:29:06
to check is that if the given i if is still less than uh string.length minus
2:29:14
one. basically uh we will first try to check that whether the given string for
2:29:21
two values does its value exist or not. So now we will check that if this two
2:29:27
symbol strings if that is present inside our hashmap we are going to add the
2:29:32
value of sum and also we are going to update the value of i by values of two
2:29:39
because we are already taking consideration of two values and then we will move on to the next value inside
2:29:44
our loop and say for an example for some reason that is not the case in that case all we
2:29:53
will have to do is we simply simply need to add one value. Uh so once our loop ends, we should have
2:29:59
our answer populated in the sum variable. So we can simply return sum.
2:30:05
And now let's try to run this code. Seems like our solution is working as expected. Let's submit this code. And
2:30:11
our code runs pretty fast compared to lot of other solutions. And it is also very efficient in terms of time
2:30:16
complexity and space complexity. So I will be posting the solution in the comments so you can check it out from
2:30:22
there. Thank you.
2:30:30
We are still not employed by a fang company. So let's not stop late coding till we get there. Today we are going to do verifying an alien dictionary
2:30:36
problem. And this problem has been really interesting problem and it could be a prefix to lot of other kind of
2:30:42
problems that I will be posting in the future. If we see the number of companies that have asked this question,
2:30:47
it's not too many companies but thing is the companies that do they are one of my dream companies. So that's why I'm
2:30:53
paying my utmost attention to it. We can see that Facebook, Uber, LinkedIn, Amazon, Apple, eBay, uh, Bloomberg, Bite
2:31:00
Dance, they have all asked this question. So I'm not going to skip it. So we are given an alien language and we
2:31:07
are told that they are using all the English lowerase letters. Now we are given uh some words in that alien
2:31:14
language and we are also given the order of alphabets that that those particular
2:31:19
alien language follows and we need to see that whether those words that we are
2:31:24
originally given are they sorted lexographically graphically or not. Lexographically means essentially how we
2:31:32
are going to store them in a dictionary. Uh suppose we are talking about the plain English that starts with a b c d
2:31:38
and ends at z. So if we are given two words something like uh bat
2:31:44
and cat. So question is are they lexographically sorted? Yes. Why?
2:31:50
Because b comes before c. So that's why if we want to put this in a dictionary
2:31:55
we will we would have stored bat before storing cat. So this is lexographic
2:32:00
graphically sorted. Let's take another example. Suppose we are taking an example of bat,
2:32:07
cat, dog, elephant.
2:32:12
Are they are all of these words sorted uh lexographically? Well, we just need
2:32:18
to check that what is the order. So in order to check the order, first we only
2:32:23
need to compare the first element. So B comes before C. So we are good over here. Now C comes before D. So we are
2:32:31
also good over here. and D comes before this E. So we are also good over here.
2:32:36
So we check all the words and we check that they are sort they are sorted in lexographically. We can return true in
2:32:43
this case as well. Well suppose we are given another example. Suppose we are given bat and Batman. Well in this case
2:32:51
if we if we check the first letters they they both are same. Even if we check the second letters they both are same. Uh
2:32:57
the third letters they both are same. But the thing is now over here we find an empty list where there are no
2:33:04
elements and over here we still have some values which means we can say that this word one is actually prefix of word
2:33:13
two because this bat is actually common and
2:33:18
then we have some additional elements which means that word one is actually prefix of word two and in this case even
2:33:25
if we want to put this in a dictionary bat will be first one to be in the dictionary and Batman would come later
2:33:32
down in the dictionary because this is actually uh this is how language works. This is how dictionaries work. So uh in
2:33:39
this case we will also return true. But thing is if the reverse was given if we
2:33:44
were given something like Batman and we were given bat we wouldn't have returned
2:33:49
true in this case. Why? Because this particular element we check bat bat this
2:33:55
is good. But the thing is over here we have M and over here we have we would have an empty we would have an empty
2:34:01
string. So that's why at this particular location the words are not sorted
2:34:06
correctly. So this is one scenario where we would return false. What could be the
2:34:12
what could be more scenarios where we we need to return false. Well of course if the words are given something like uh
2:34:18
suppose we are given the words like ESPN and DSPN.
2:34:24
Well, in this case, we if we analyze the first element, we can clearly see that
2:34:29
uh D should come before E. But the thing is in this the words are put in the
2:34:35
reverse order. So over here we would return false. If we take another example, suppose we
2:34:41
are given one another two words like batwoman and Batman.
2:34:49
Well, in this scenario, first we will compare the first two letters. BB is common. A A is common, TT is common.
2:34:56
Which means up until this point we cannot determine like they seem to be in order, right? But thing is over here we
2:35:01
find this W and over here we find this M. Essentially in English language W
2:35:07
comes later than M. But thing is over here we had this W come in first before
2:35:13
this M. Which means in this case we we cannot return true because we find a mismatching pair. So we we can return
2:35:19
false. Okay. So now we have now we have exhausted all the possibilities where we
2:35:24
can return false. We can return false if the words are same like if one word is
2:35:30
prefix of another word but thing is the smaller word comes later in our uh sequence than the first word we can
2:35:38
return false in this scenario. If the ver if we find at any point that there exist mismatching pairs at the beginning
2:35:44
we can return false or at any point somewhere in the middle middle if we find a mismatch mismatching pair between
2:35:51
two words that are adjacent to each other we can also return false. Now these are the scenarios where where we
2:35:58
need to return false and if that is not the case if all the words are sorted uh lexographically we can return true and
2:36:05
this was true for plain English. The thing is even the same thing applies to the alien dictionary as well that in the
2:36:11
alien dictionary the order of words we are given and we only need to see that
2:36:18
whether the words that are given do they follow this particular order or not. So if we take the take take an example over
2:36:24
here we are given two words hello and lead code. So if we see we only need to compare the H and L because those both
2:36:31
words are not same which means we can compare them and over here we see their order. So H comes before L which means
2:36:38
that these two words they are in correct uh lexographically sorted order. If we
2:36:45
take the second example over here we are given the word word and over here we are
2:36:50
given the word world. Now w they are both same. O they are also both same. R
2:36:58
they are also both same. Now what is the first differing character? The first differing character over here we have is
2:37:03
D. And the first differing character we have over here is L. Now we check in this particular sequence that where is D
2:37:10
located? So D is located over here. and L is actually located over here which
2:37:15
means L comes before D. But the thing is over here that is not the case. Over here we get D come before L. So that's
2:37:22
why in this this scenario since the moment we find the first differing word we immediately return false. We don't
2:37:29
even have to worry about checking out this row word. So this is how this problem is to be understood.
2:37:36
And let's see that what would be the approach to solve this problem.
2:37:43
Okay. So suppose we are given an example like this and uh these are the number of words that we are given that we need to
2:37:48
compare. Now the first approach we can do is that in this particular order the most important thing is to find the
2:37:55
position of words that where the words are stored and the best thing we can do is we can create an additional data
2:38:02
structure something like a hash map and in the hashmap as part of the key we are
2:38:08
going to store whatever the uh letter is and uh in the value portion of the
2:38:14
hashmap we are going to state that what is the position of that particular letter inside this given order list. Now
2:38:21
what we are going to do is we are going to iterate over this order and we are going to fill up this hash first. Now uh
2:38:27
first of all so if we fill if we start filling it up we will see something like this that this w is at zero position. Uh
2:38:34
this uh second element C is on first position. This the next element A is on
2:38:39
second position and B is on third position and uh D is on fourth position
2:38:45
and so on and so forth. Now since we have this available to us or all we need to do is we need to iterate over all the
2:38:52
words. What we are going to do is first we are going to check whatever the adjacent words are. In the adjacent
2:38:59
words first we are going to check that what is the first letter are the first letter same or different? If they are
2:39:06
different then we need to check their position from this hash set. So what we are going to do is over here the first
2:39:12
two letters we are given are W and C. So we check that this W what is the
2:39:18
position of W? The position of W is zero. And what is the position of C? The position of C is one. So 0 should come
2:39:24
before one. That is okay. Which means that this will is actually in correct position by the reference of this C. So
2:39:31
we can ignore this case. We can say that okay will is at correct position because
2:39:37
W is less than the value of C. But thing is we cannot return true immediately
2:39:42
because there are still words that we haven't checked. So again we are going to check with Chris with this bat word.
2:39:49
So first we are we will check that okay what is the first letter over here? So first letter over here is C. What is the
2:39:54
first letter over here? The first letter is B. So they are not same. They are different which means we need to check their position. So the position for C is
2:40:03
at value number one and position for B is at value number three which means one
2:40:09
is less than three. So that is also good. Which means now we can see that this Chris is in correct position. Now
2:40:15
we will check this bat with this Batman. Okay. So first we will check for this B
2:40:22
and B. So they both are same which means we can't compare. Again we are going to check this A with this A. Again they are
2:40:29
same. We can't do anything. This T with this T. Again they are same. We can't do anything. Now over here we have reached
2:40:35
the end of our uh request. But over here we still have some words that we need to compare to. So we can define that this f
2:40:42
first word is actually a prefix of the second word. Since this is a prefix which means that this is in correct
2:40:49
position uh in terms of lexographically sorted manner goes. So we can ignore
2:40:54
this case as well. We can say that okay this bat is also at correct position. And now we need to check this back man
2:41:01
with this bat woman. So again we repeat the same process. We check the first element. So b is at correct position.
2:41:08
Now again we check the second position. this a they both are same so there is no point in comparing them. Again we check
2:41:14
this t uh they both are also same so there is no point in comparing them. Now
2:41:19
comes the interesting part. Now we are at this position M. So over here the
2:41:24
word is M. Over here the word is W which means that M and W they are both the
2:41:31
first differing word the first letter amongst these two words they are not the
2:41:37
same. So which means we are going to check their position in this hashmap again. So we know that this position of
2:41:43
W is actually zero and this position M so I haven't mentioned it over here but
2:41:50
it falls somewhere over here which means that this value would be somewhere at least over 10 to 15 letters somewhere
2:42:00
around that but thing is we know the position of W is at zero and this position is actually much greater than
2:42:06
whatever the position of zero is uh so let's say it's 13 something like that so We can declare that this M is not in
2:42:14
correct place compared to this W because this W is zero which means that this bat woman should have been in this place
2:42:21
rather than this Batman. So because we have found this we can clearly say that there is a mismatch between uh the
2:42:29
adjacent words where the first differing letter is different. So in this case we
2:42:35
can simply return false. And uh if suppose we were given an example like
2:42:41
this over here we would have compared this bad bad and they were same. So we
2:42:46
wouldn't have done anything. And now we would be com comparing this W with this M. So we would say that okay W is at
2:42:52
zeroth position. M is at 13th position. So uh 0 is less than 13. So this is also
2:42:58
good. And now we have reached the end of our loop. So because there are no other words to compare to we can say that okay
2:43:03
now we have reached the end word. Which means that over here we can return true. So if this was the sequence given we
2:43:11
would have returned true but that was not the case and so over here we would have to return false and this is the
2:43:16
most basic approach that we can take and this is the most optimal approach as well. If we calculate the time and space
2:43:22
complexity for time complexity essentially first of all we are iterating over this entire order. So we
2:43:28
are doing n work and uh then we are iterating over all the words which means
2:43:34
again that is also we can consider as n work. So time complexity would be bigo of n where n is actually the number of
2:43:41
words that are given and if we calculate the space complexity that would also be bigo of n because we
2:43:48
will have to create an additional data structure where we are storing all the letters and their corresponding
2:43:53
positions and this is a very effective solution. Now the thing is this was an easy problem and uh of course we can
2:44:01
clearly see that this was an easy problem but the thing is most of the companies they don't ask this problem
2:44:06
only they ask this problem in tandem with another uh verify alien dictionary
2:44:12
problem uh that requires graph theory knowledge. So I will be making video on that soon. So you can check it out uh
2:44:20
that from there that that how can you how can you keep both the questions in t tandem because most of the top level ID
2:44:27
companies they are only going to ask you question first and then they are going to ask some follow-up questions that
2:44:32
would be more difficult than the original question.
2:44:39
So first of all we are going to create a new hashmap
2:44:44
and we are going to name it order map. Now we need to iterate over the given
2:44:51
input order and we will have we will be filling out the position for every
2:44:56
single character in our order map uh hashmap that we have just created.
2:45:04
Okay. Uh after this loop runs our order map hashmap would be filled and now we
2:45:10
will have to iterate over all the words and inside every single word we will have to compare it with uh its adjacent
2:45:17
word uh character by character. So
2:45:27
notice over here I'm choosing length minus one because we if at any point we reach to the last word we don't need to
2:45:33
compare that and since we are comparing two adjacent words um we don't want to
2:45:39
go out of bounds so that's why we will check one word less in our for loop and
2:45:45
now I'll create another for loop and that is to iterate over uh every single
2:45:51
character between two adjacent words.
2:45:57
Okay. So first of all we are going to check that if at any point the current J
2:46:02
we have if that is greater than or equal to whatever word the adjacent words
2:46:09
length we have.
2:46:17
If that is the case which means that we have found a prefix where the next value
2:46:23
is actually lesser than the previous value. Uh so if we take an example this
2:46:30
would be the scenario if we are given Batman and the word bat. So in this case
2:46:37
eventually we would reach to this m uh this particular m value where the length
2:46:43
of the current j would be greater than length of whatever the next value we are at and if that is the scenario we will
2:46:50
return false. Okay if that's not the case uh we need
2:46:56
to check we need to compare letter by letter. So first of all we are going to see that whether the current word we are
2:47:03
at
2:47:10
if that is same as next word or not.
2:47:16
Okay if that is the case and if two both the words are not same we will have to compare their positions. So first I'm
2:47:23
going to create two parameters. So one is for current letter
2:47:28
and I'm going to fetch the value from the hashmap we have created.
2:47:47
And for the next word we will also get the position.
2:47:55
And now we simply need to compare that if the next letter
2:48:03
if that is less than the current letter.
2:48:10
If that is the case which means we have found a mismatch and we can return false immediately.
2:48:17
And if that is not the case, which means that we have found a
2:48:23
matching pair and we can break out of the current word.
2:48:29
And after this loop ends and if we are at the last word and if we were we are
2:48:36
able to successfully get out of the loop, we can simply return uh true.
2:48:42
And uh let's try to run the code. Oh, we need to return false
2:48:52
is less than order. Length
2:48:57
silly spelling mistake. Okay, seems like our solution is working. Let's try to submit the code.
2:49:04
Okay, our solution works pretty efficiently and I will be posting this code in the comments. You can check it
2:49:10
out from there.
2:49:18
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. Uh today we are going to do longest consecutive
2:49:24
sequence problem and this problem has been asked in Google, Microsoft, Facebook, Apple, uh Goldman Sachs, Uber,
2:49:32
Twitter, bite dance. So it's lot of companies and lot of huge ID companies that have asked this problem. So I I'm
2:49:40
going to pay my most attention. I hope you also do it. And uh I have I just have one request for all of you guys.
2:49:46
Like uh my YouTube channel if you see most of the people they are not even subscribed and uh it takes a lot of time
2:49:53
and lot of effort to make these videos. So I would really appreciate if you can just sub subscribe like
2:49:59
uh basically we are given an unsorted array of integer nums and we need to
2:50:04
return the length of longest consecutive elements inside the sequence. uh also we
2:50:10
there could be possible that there might be duplicates in our given unsorted array. So we just need to take care of
2:50:16
those as well. And let's uh try to understand this with an example. So the example we are given over here is
2:50:23
and over here if we find that what is the longest consecutive sequence we can find the longest consecutive sequence we
2:50:29
can make is 1 2 3 4 amongst these values. And we can ignore just uh this
2:50:36
100 and 200 because there does not exist any consecutive sequence from those values. So over here uh since we found
2:50:42
four elements we can return the length of this as four and this would be our answer. Uh same way if we take another
2:50:49
example over here we are given nine elements and all nine elements are actually part of the longest in longest
2:50:56
consecutive sequence. So in this scenario we are going to return nine.
2:51:01
So in the brute force approach we are not going to do anything clever. We are just going to take the most basic approach that we can and try to find the
2:51:09
longest consecutive subsequence. So suppose at any moment we are given an
2:51:14
input like this. We are given an empty list. We can say that there exist zero longest common subsequence elements and
2:51:20
suppose we are given an element like this. Suppose this is 100. We can say that there exist exactly one longest
2:51:26
common subsequence element uh in this given input. So that is a given right? that even if with a single element we
2:51:32
can at least define that there exist one single longest common subsequence element. Now over here in this example
2:51:40
since we know that there are at least more than zero elements uh in this given input and initially we are at this 100th
2:51:47
position which means that we can say that the current longest consecutive subsequence we can find is one and now
2:51:54
if we want to find a subsequence in the remaining group that cons that consists
2:52:02
this 100 how can we do it like we can only do it in one scenario that in this
2:52:07
remaining portion in this remaining elements if there exist element 101 if this exists we can say that 100 is also
2:52:14
part of the uh or could be part of the longest consecutive subsequence. So this
2:52:20
and this would be our basic approach that at every single position we will try to find that whether the next
2:52:26
elements could they be in the in the remaining input and if they do we will
2:52:31
update our longest consecutive subsequence and uh whatever the maximum value we find we are going to return it
2:52:37
as our answer. So we will also create another variable called current
2:52:43
subsequence and that would take care of what is the current subsequence that we are trying to find. Let's just name this uh
2:52:50
current. Okay. And initially the current subsequence is also at also one over
2:52:56
here at this 100th position. Now we'll try to see that whether this 101 rem
2:53:01
exists in the remaining portion and it does not exist. Which means we will move forward. So we'll move forward with the
2:53:09
element four. Now for this element four we need to see that whether element five
2:53:14
exists or not. So element five also does not exist. So we'll move on with this 200. For 200 we will see whether two
2:53:21
2011 exists. This also does not exist. For this one we will try to see that whether two exist. So two exist in the
2:53:29
remaining array. Now because two exist the current subsequence we had was of
2:53:35
value one. We will update it to value two. Now because this two exist exist we
2:53:40
can not break right now. We'll try to find more values. So we will again try
2:53:45
to see that whether three exist and three also exist which is over here. So again we will update this value to
2:53:51
three. Again because three exist we will try to see whether four exist. Four also exists and it is present over here. So
2:53:58
we will update the current value of longest consecutive subsequence we have found to four. Now we will try to see
2:54:05
whether five exists. Now five does not exist which means that four is the longest we have found so far. And uh
2:54:11
then we will try to update the value of longest consecutive subsequence you have found to whatever the current value is
2:54:17
because previous value of this was one and now this new value is four. But we
2:54:23
are not done yet. We have only check up until this one. So now we will check for this two. So again for this two we will
2:54:31
and by the way we will re evaluate this value back to one because now we are
2:54:37
starting with the new element. So again for this two three exists so we will update the value to two and uh four also
2:54:44
exists so we will update the value to three. Uh but we cannot update the longest common subsequence because four
2:54:50
is greater than three. And now we again check for this value number three. So for value number three four also exist
2:54:55
which means that this value would become two for this value number three but we won't update and in the end we are going
2:55:02
to return this four. So this is our brute force approach like this solution works. If we get the desired answer, the
2:55:08
thing is we get the desired answer at a very bad cost. Like even if we just try to calculate the time complexity in this
2:55:14
case, the time complexity would actually be bigger of n cq. Why n cq? Because we
2:55:20
will need to iterate over every single elements at least once to find the longest common subsequence. So that is n
2:55:27
amount of work. Then suppose over here we are initially at this position 100. So we wanted to
2:55:34
check that whether 101 exists. So in order to do this check we will have to also have to iterate over the entire
2:55:39
loop. So then in that case we will have to do n more work and at any go any
2:55:45
given moment suppose over here we identify that this for this one two also exist right and once we identify that
2:55:52
two exist we will again check whether three exist again we will check whether four exist again we will check whether five exist. So even to do these checks
2:56:00
we will have to do n more work. So again we will do n work. So in total we are going to do n * n * n so n cube work to
2:56:10
solve this brute force approach and this is a very disastrous solutions.
2:56:15
Now one better approach we can think of is suppose that with the given input if we do some sort of modification can we
2:56:21
come up with better solution in faster time complexity like of course we can.
2:56:26
Uh so remember that what we are needed over here is that we need to find the longest consecutive subsequence of this
2:56:34
given input and we are going to see with this custom example how can we modify the input and uh how can we come closer
2:56:42
to solution. So suppose in this given example rather than keeping the input just like this if we do sort the given
2:56:51
input things become much easier for us and let's see that what would be the sorted result.
2:56:58
Okay. So now we have our sorted result. Now in the sorted result we simply need
2:57:03
to find that what is the longest common subsequence that exists longest
2:57:09
consecutive subsequence that exist. And it's pretty simple to find now because all we need to do is that at any point
2:57:16
we know that the definition of uh common subsequence is that suppose we have we
2:57:21
are currently at the value I then I + 1 would be a common subsequence then I + 2
2:57:28
would be a common subsequence and this is the only condition we have to take care of and the only other thing we need
2:57:34
to worry about is having two duplicate values right next to each other. If at any point we encounter two two duplicate
2:57:40
values, we simply ignore one of those values and move move forward. So in in this example, we are only going to do
2:57:47
two checks uh with the sorted input. First check we are going to do is at first position we are going to check
2:57:52
that whether this position is exactly same as whatever the previous position we had. If that is true, we would skip
2:57:58
over because we don't need to uh do anything with that because there are two consecutive two same values. And if that
2:58:05
is the case, so which is the case in this scenario that both values are same which means we would skip over. So we
2:58:11
would go to the next element and now we are at this next element. Again we are going to check that the value we are
2:58:16
currently at and the value before that if they are same or not. So in this case they are not same. If they are not the
2:58:21
same we are also going to check one more thing that whether the current value of a of i. So suppose this zero is actually
2:58:29
a of i and minus whatever the value of a of i -1.
2:58:36
So a of i -1 in this case is minus1. So if difference between these two values
2:58:42
if it becomes exactly one which means we can conclude that these two values are
2:58:47
part of the longest common subsequence and uh we could update their value.
2:58:52
Again is again like brute force we are going to use two variables. one variable to keep track of longest common
2:58:58
subsequence we have found so far and second one is to keep track of the current uh subsequence that we are
2:59:03
working on. So let's see that how how it would work and both both the values would be set up as one initially. Now
2:59:11
initially we are at this zero and one pair and because they are sorted we know
2:59:17
that they are always they are always going to be adjacent to each other. So this is the only condition we need to worry once we identify that the both
2:59:23
values are not same. So in this case we can say that uh the current longest uh the current subsequence we have found is
2:59:30
actually size two. So we can update the value over here that this is this is two. Now again we check with this value.
2:59:38
Now this value again it's zero and it's the same as this one. So we ignore ignore it. We don't need to do anything.
2:59:44
Now again we check with this value. So this value is actually two. Now with this two if we put down this equation so
2:59:51
2 minus 0 this is not equal to 1 which means that uh this 2 and 0 are not part
2:59:58
of the common subsequence uh if they are not part of the common sequ subsequence we we check that now we can't update
3:00:04
this current anymore. So we check between the current and longest common subsequence we have so far and the
3:00:10
current is actually greater which means we will update the longest consecutive subsequence to two as well. And now
3:00:16
current we will put it back to one because we will repeat our our search
3:00:22
again. Now we are at this position three. So 3 and 2 are not same. And uh 3
3:00:28
minus 2 is actually 1 which is true which means we update our current. So
3:00:34
current would become 2. Now we are at this four. Again 4 - 3 is
3:00:41
equal to 1. So again we update our current to three. Again we are at this five. So
3:00:48
again we need to update our current. So current would be updated to four. Uh
3:00:54
because all of these values 2 3 4 5 they are in a common subsequence. Now we are
3:00:59
at the seven. So 7 - 5 they are not equal to one which means we we can't
3:01:05
update the current. So we will need to reset the value of the current. So before resetting the value of the
3:01:10
current we are also going to check that whether the longest common subsequence needs to update and this needs to be updated to value four because this this
3:01:17
one was four before because of these four values. And now we can set this value to one again at this position 7.
3:01:24
And now we are at this position 200. So 200 and 7 they don't have any correlation. So we can't do anything
3:01:30
about it. And in the end at the end of the loop we are simply going to return whatever the longest common subsequence
3:01:36
or current subsequence whatever the maximum value we have found between these two. And in this case the maximum
3:01:42
value we have found is actually four. So this would be our solution. Now this solution works pretty efficiently. It's
3:01:48
pretty neat. And if we see the time complexity we can complete everything in just one single iteration. So we are
3:01:53
only doing n work. But the thing is the time complexity in this case would be go of n login because initially remember
3:02:01
that from this given input we will actually have to sort the array as well and sorting takes n login time. But
3:02:08
overall if we still compare it with whatever the brute force approach we had brute force was actually big go of n cube. So this was really bad time
3:02:15
complexity and this is much more and much bigger improvement upon our uh scenario.
3:02:22
Now in the optimal solution we are actually going to try couple of things. Uh first thing we are going to do is we
3:02:27
are going to create an additional data structure called hash set and in the hash set we are going to enter all the
3:02:34
values that we have found from this array. So suppose we create a hash set something like num set. Now in in this
3:02:41
hash set we are going to add all of these values.
3:02:47
Now because we have our hash set ready, what we are going to do is uh when we are going to iterate over this hash set
3:02:55
and we are only going to start checking for the longest consecutive subsequence
3:03:00
from the elements that could be at the start of the ele start of the longest common subsequence. And what elements
3:03:07
can be start of the longest common subsequence? So if we take take this example, we can
3:03:12
actually see couple of uh common subsequences or consecutive subsequence.
3:03:18
One consecutive subsequence we can find is 99 and 100 which is at these two
3:03:23
positions. And second consecutive subsequence we can find is actually 1 2
3:03:28
3 and 4. Now in the what we were doing in the brute forces we were checking at
3:03:34
every single position that what would be the uh longest common subsequence we can
3:03:39
find. The thing is we can only find longest common subsequence from the first element of the start of this uh
3:03:46
consecutive subsequence. Same goes over here that whatever the subsequence we
3:03:51
can find at this value number 100 the subsequence that we can find at value number 99 would always be greater than
3:03:58
whatever we can find over here because this by itself is already a subsequence. So we are going to use this logic like
3:04:05
over here if we put this 3 2 3 4 we will only find the consecutive subsequence of
3:04:10
length two but this 2 3 4 would have would be three uh would be of length three and this 1 2 3 4 would actually be
3:04:16
of length four. So we can only find the maximum consecutive subsequence at the
3:04:22
start of the uh any uh sub any subsequence not and not somewhere in the
3:04:28
middle. And the only way to check that whether we are at the start of the subsequence or not is by just checking
3:04:36
one very simple uh condition that at any point we check that whether the exact
3:04:41
value before that value like one value before the value we currently are at if
3:04:46
that exists which means that we are not at the start of the common subsequence. Let's take it by an example over here
3:04:52
and let's see that what would be our approach. So first of all we are going to be at this position 100. We are going
3:04:57
to check that whether this 100 is a start of any consecutive subsequence or not. So we check that whether in this
3:05:03
given num set does the value 99 exist. Now we know that 99 exist. So because 99
3:05:10
exists 100 cannot be at the start of the common subse consecutive subsequence. So
3:05:15
we are going to ignore this case. We don't have to do anything with this 100. We come up at 99. Now we come up at this
3:05:22
99. We check that whether there exist a value before 99. So 98 does it exist in
3:05:29
this num set? 98 does not exist. Which means that at 99 we can be at the start
3:05:34
of any common consecutive subsequence. So we start a subsequence at 99. And now
3:05:40
we will initiate initiate our logic and in our logic we are simply going to check that from this 99 how many
3:05:47
consecutive numbers we can reach. So we are going to check that okay 99 by itself is a common subsequence of length
3:05:54
one. So we know that now from this 99 we are going to check that can we reach value number 100. So 100 we can reach
3:06:01
and because we are using a hash set we can do all the operations in constant time. So we are not adding any strain in
3:06:08
our time complexity. Now we can find the value 100. So we can reach 100 which
3:06:14
means that the whatever the longest common subsequence that we longest consecutive subsequence we found we will
3:06:19
increase its value to two. Now again we will try to see that whether we can find 101 like 101 does not exist which means
3:06:27
we would break out of over here and the longest common sub uh sub subsequence we have found up until this point is
3:06:33
actually of length two. Again we are going to repeat the same process. So now we are at this position
3:06:40
four. We check that whether four uh whether three exist in the set or not. So three exist which means we ignore
3:06:46
this four. Now again we are at 200. So we check that whether 199 exist. So 199
3:06:52
does not exist which means 200 can be start of the any consecutive subsequence. So we again check that
3:06:58
whether 2011 exist but 201 does not exist in this given example. So we
3:07:04
ignore this 200 as well because the longest consecutive subsequence we find at this value number 200 is always going
3:07:11
to be one and we already have a value that is greater than one. Again we check at this position one that can one be
3:07:18
start of any consecutive subsequence. So we check that whether the one minus one.
3:07:24
So we check whether zero exist in this uh example or not. Zero does not exist which means one can be start. So now we
3:07:32
set our current uh subsequence to value number one. And now we check that from
3:07:38
this value one how many other values we can reach to. So first we check that can
3:07:44
we reach the value number two. Yes, we can reach value number two because two already exist. So we update whatever the
3:07:50
current subsequence we can find to two. Now from this two we check can we reach three. Again we can reach three. So we
3:07:55
will update the current value to three. Again we check that whether from this three can we reach four and yes we can
3:08:02
reach four as well. So again we will update the value of our four uh value of the current subsequence to four and from
3:08:09
four we check whether we can reach five. So five we can't reach which means we are at least able to reach this four. So
3:08:16
we are able to see that the current subse the longest current subsequence we
3:08:21
have found is four and previous value was two. So we will update this. So this
3:08:26
will become uh four. And now again we are going to check the same thing for
3:08:31
this value number two. So that for value number two does one exist and one exist. So we we will ignore this. Again we
3:08:37
check for three. Does two exist? two also exist which means we are going to ignore this three and now since we have
3:08:43
reached the end of this hash set so we are going to reach whatever we found in the as the longest consecutive
3:08:49
subsequence and this would be our answer. Now if we calculate the time complexity the time complexity would
3:08:54
actually be big of n in this case because we are only iterating over the entire uh input just once uh through
3:09:01
this hash set. Uh so this this is a very efficient time complexity and if we see the space complexity the space
3:09:08
complexity is actually big of n because we will have to create this additional num numerical set and we are going to
3:09:15
store n memory for that and uh let's see the coding
3:09:25
I will be showing the hash that solution in this code uh but I'm going to post both the codes in the comments so you
3:09:30
can check it out from there. So first of all we are going to check that whether we are given an empty list or not.
3:09:37
If that's not the case uh first of all we are going to create a hash set.
3:09:42
We are going to name it num set. Now we'll run a loop it across the the
3:09:49
given input and we are going to store all the values to to our hash set.
3:09:57
This is going to do two things. uh it's going to eliminate all the duplicates values and uh it will only add unique
3:10:03
entries in the hash set because hash set has a property that does not allow us it
3:10:09
to store duplicate values. Now we are going to create a parameter
3:10:14
to store the longest subsequence and we are going to initialize it with
3:10:19
value one. Now we are going to run a for loop across the given num set. So,
3:10:26
so initially we are going to check that whether we are starting from the middle of any longest consecutive subsequence.
3:10:32
If that's the case, we are going to ignore that uh number. So
3:10:38
if this condition is true, we are going to uh continue and go to next element in
3:10:43
the loop. If this is not the case,
3:10:49
we are first of all going to mark the current the number we are at as current
3:10:55
number because this is the beginning of any uh
3:11:02
longest consecutive subsequence. We are also going to create another parameter called current sub that is going to take
3:11:08
care of uh the current maximum uh consecutive subsequence we can find. And
3:11:14
we are only init we are going to initialize it to one. And now we are going to put a condition that while
3:11:21
uh our hash set contains
3:11:31
the current number plus one.
3:11:36
While this condition is true, we are going to increase the number
3:11:44
and we are also going to increase our current subsequence.
3:11:51
And after this loop ends, we need to check that whether we have found the longest common subsequence or not. So
3:12:00
once this loop ends, uh we should have our answer in the longest sub variable.
3:12:05
So we can simply return that.
3:12:11
Let's try to run this code.
3:12:27
Okay, seems like our solution is working. Let's try to submit the code.
3:12:32
And seems like our solution works pretty well. and uh it is faster than lot of other solutions. I I will also post the
3:12:40
the sorting algorithm solution as well. So you can check it out from the comments.
3:12:54
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better at technical interviews. Keeping with
3:13:00
that goal in mind, today we are going to do a very interesting lead code problem called first missing positive. And if we
3:13:06
see some of the popular companies who already asked this question, there are companies like Amazon, Microsoft, Google, Apple, IBM, Tik Tok, Hudson
3:13:14
River Trading, Bite Dance, Twitch, Facebook, Uber and Snapchat. So that's
3:13:19
why I'm paying my utmost attention. I hope you also enjoy the video.
3:13:24
So this is a lead code hard problem and also very well-like problem on lead code. Basically, we are given an
3:13:29
unsorted integer array called nums and we need to return the smallest missing
3:13:35
positive integer. So, the problem statement is really small and easy to understand. The tricky part in this
3:13:40
problem is that we are being asked to solve this problem in big of n time with a constant extra space. So, time
3:13:47
complexity has to be big of n and space complexity has to be big of one. So, this is the difficult part that we are
3:13:54
trying to achieve. Now first let's try to understand this with few examples that what does this problem is asking us to do. So in this case we are given a
3:14:01
numbers array and in this case the values are these. Now we are trying to find the first missing positive number.
3:14:07
Okay. Now what is the first positive number? First positive number is going to be one. Then what is the second
3:14:13
positive number? It's going to be two. What would be the next one? It would be three. Now in this case since 1 and two both are present three is the first
3:14:20
missing positive number. So we need to return three as the answer. If we take a look at the second example again in this
3:14:27
case we have one present but we do not have two present. So because two is going to be the first missing positive
3:14:33
integer. So in this case we don't even need to check for all the remaining ones. Two is going to be the answer that
3:14:38
we need to return. And same goes with this example. In this case since we don't even have one as the answer we are
3:14:46
definitely going to return one as the answer because one is the first missing positive number. Okay. So the problem
3:14:52
statement is really easy to understand. Now let's see that what could be the possible different approaches we can take in order to solve this problem.
3:15:00
Well the first approach that comes to our mind is a brute force approach. In the brute force approach what we are going to do is we will try to find the
3:15:06
first positive number. So first positive number is going to be one. We will see that whether one is present in this or
3:15:11
not. Okay. So one is currently present. So now we will move on to two. Two is also present. So then we will move on to
3:15:17
three. So value number three currently is not present. So we can say that three is the first missing positive number and
3:15:23
we will return three as the answer in this case. Right? But the thing is what is the issue with this brute force approach? Well uh the issue is quite
3:15:29
simple. Time complexity is actually going to be big of n² which is disastrous. So we do we will have to do
3:15:35
something better than this. Let's try to find another approach and see if we can do something better. So say for example
3:15:42
suppose this is the given input. uh the idea is that if for this given input if we somehow sort this input we would
3:15:49
actually able to do something better. So let's just sort see the sorted result. All we need to do is go to the first
3:15:55
positive integer. So in this case first is 1. One is present over here and then move to all the other elements until we
3:16:01
find a place where the next element is missing. So in this case we can clearly see three is missing. So three is again
3:16:07
going to be the answer for the sorted approach. So sorted approach works better than the brute force solution.
3:16:12
But the issue with the sorted approach is that from given input in order to generate the sorted array uh it takes us
3:16:18
the time complexity of big of n login just to generate the sorted approach and
3:16:23
then we will have to iterate over it once. So the thing is this time complexity is still more than what we want. So this is this approach is also
3:16:30
not going to work. Let's try to see some better approach.
3:16:36
Okay. Now before we go to the next approach first let's try to make uh things much easier to understand.
3:16:41
Suppose if we are given any input and if all the values are starting from one
3:16:47
only positive values that are incrementing in sequential order. What would happen in this case? What would be
3:16:54
the first missing positive in this case? Well, definitely the first missing positive in this case is going to be
3:16:59
value number five. Why value number five? Because currently the given input n only has four characters and all the
3:17:06
characters are like 1 2 3 4. So the minimum possibility is that the value
3:17:13
could be five or it could be any single value from uh starting from 1 to 4. So
3:17:20
basically all the values that are concerned of us is that the first
3:17:26
missing positive will only be between the given n + one. So from 1 to n +1 is
3:17:36
the possibility where the first missing positive value lies. Uh in any other any other values are no use of us. So say
3:17:44
for an example if we are given input n where the values are such as like -1 -6
3:17:51
then + 8 then 1 2 something like this. If this is the possibility definitely
3:17:58
the first missing positive in this case is going to be value number three. But the thing is since here there are only
3:18:04
five values the first missing positive number can only lie between the values
3:18:09
of 1 to six nothing more than that. So if that is the case why are we even
3:18:16
concerned with all the values that are not between 1 to 6. If say for an example values like these three we are
3:18:22
not concerned with them and I already explained you why we are not concerned with them because we are actually going
3:18:27
to use it in one of our next approaches. So say for an example if this is the input we are given uh previously for the
3:18:35
sorting and also for the brute force what was the issue happening? The issue was happening that if we want to search
3:18:40
that whether value number one exist inside this given input or not it was causing us lot of time. So what if we
3:18:46
speed up this process we can actually speed up this process by creating a hashmap. And what would we do inside
3:18:54
this hashmap is that at any given position we will first try to identify
3:18:59
whether one exists or not and one is not if one is not existent definitely we are
3:19:04
going to return one as the first missing positive that is going to be our answer that is going to be the most simple case scenario but if one is present then we
3:19:12
are guaranteed that the value of first missing positive is going to be between 2 to 6. So any value that does not lie
3:19:20
between the values of 2 and six we can simply denote their value as one inside
3:19:25
our hashmap and then we will do something tricky with our hashmap. So let's apply this logic to our hashmap.
3:19:33
Let me quickly draw the hashmap from given input. And by the way for any particular value this is going to be the
3:19:40
key and its subsequent value is also going to be same except for these three values where the value is going to be
3:19:46
one. So this is the hashmap we have been able to generate from our given input n
3:19:51
where the key is the same value as the values inside our uh array and it
3:19:57
subsequent value we have done some modification and all the other positive values they are equal to whatever their
3:20:04
subsequent values are. Now all we need to do is we know that the answer could only be lying between 1 to six nothing
3:20:10
more than that for the first missing positive. So we will run a loop starting from value number 1 to six and we will
3:20:16
try to see that whether all the values between like including 1 and six between 1 to six are they present inside this
3:20:22
hashmap or not as key and we would be able to do this in constant time because that is one of the property of the
3:20:28
hashmap and that is going to make our lives much more easier. So first we will try to see that whether one exists
3:20:33
inside the hashmap or not and definitely one exist over here. So we can simply return simply go to the next element. So
3:20:39
we will check whether two exist or not. two also exists. So we can simply go to the next element and we will check whether three exists or not. Since three
3:20:46
does not exist inside the shash map, we can immediately say that three is going to be the answer that we need to return.
3:20:53
And this is a very good approach. This solves the a lot of our problems that we were facing in terms of time complexity.
3:21:00
Why? Because it takes bigo of end time to generate this hashmap. Okay. So in
3:21:06
order to generate the hashmap, it takes big of end time. And then in order to run this loop and to come up with the
3:21:12
answer that whether the value exists or not that also takes big of end time. So if we see time complexity basically uh
3:21:20
we have been able to complete this problem in big go of end time and this is going to be great. This is a
3:21:25
wonderful result and any single interviewer would be more than happy with this approach. But the thing is in
3:21:30
this problem uh if we see space complexity this is where the problem lies for this approach because space
3:21:37
complexity in this case is al also going to be big of why because we are creating an additional hashmap. Meanwhile we are
3:21:44
explicitly told that we need to complete this in big of one. So can we do that and the answer is yes.
3:21:55
Okay. Now let's see that what would be the optimal solution where we also do constant space uh complexity in order to
3:22:02
solve this problem. The logic we are going to keep are same that any values
3:22:07
that are too great or negative or zero we are actually going to convert them to one. Uh now let's see that in this given
3:22:14
input how many elements we are given. We are total given eight elements which means that the answer has to lie between
3:22:20
1 to 9 for the first missing positive integer which means any value that does not fall in this range we will actually
3:22:27
have to change it to value number one inside this given input. So let me create a new array. This is the new
3:22:34
array we generated. Now let's do a quick recap. Basically we first check that whether one is present or not. Since one
3:22:40
is already present, we iterated over this given input array and from that we converted this for all the values that
3:22:46
were not falling between the values 1 to 9. Okay. Now we are going to do things a
3:22:52
little bit interesting way. What we are going to do is since we already know that one is present which means we are
3:22:59
not worried about value number one. We are simply going to iterate over this
3:23:04
values. Whenever we find a value that is not one, a value that is not one, which
3:23:11
means say for an example we find this value number five. So we will go to its subsequent index. So in this case we
3:23:17
will go to index number five and whatever the value is we will just convert it into negative. Nothing more
3:23:23
than that. This is a very simple approach. So let's just quickly do
3:23:29
another uh array and we will follow the methodology I mentioned. In this case
3:23:36
the first value is five. So because first value is five we will try to find subsequent value and convert it into
3:23:41
negative. So this becomes -3. This is value number one. So we don't need to do anything again one again one and again
3:23:48
one. So since these four are one we are not going to do anything. Now this value is -3. So because this value is -3, we
3:23:55
will go to third index because this used to be a positive 3 value and remember what I said anything but one. So in this
3:24:03
case we will go to this value and convert it into negative as well. So this becomes negative 1. Now we will we
3:24:10
are okay again this value is one. So we don't need to do anything. This value is + two which means we will go to second
3:24:15
index and convert it into negative. Awesome. Now what are the things we have been
3:24:21
able to dictate? We already know that one is present which means that the
3:24:26
answer has to lie between the values 2 to 9. Now in this case since we we will
3:24:33
start iterating over from value number two to all the values remaining inside the given input array because we already
3:24:40
know that one is present. So we we don't need to do anything. And now all we need
3:24:46
to do is to check that whether that value is negative or not. And the moment we find the first positive value, that
3:24:53
index value is what is going to be the first missing positive integer. Yes,
3:24:59
this is the whole logic. Now in this case since this is negative 1, this is neative 1. So these two values we have
3:25:06
been able to dictate that why they have been turned into negative 1 because that subsequent values were present at some
3:25:13
point inside the given input array. That is why we converted them to negative 1. So we can ignore these two for this
3:25:20
particular value number four. This is a positive value. The moment we identify a positive value, this can only remain
3:25:27
positive if there was four nowhere to find in this given input. Say for an
3:25:32
example, for example, we found that this value was four. Then we would have definitely converted this to negative 1.
3:25:39
But the thing is we did not find anything and that's why we left it as positive and we have not been able to
3:25:45
find four as the first missing positive. So we need to return four as the answer and this is the optimal solution. If we
3:25:53
see time and space complexity in this case the time complexity is actually going to be big of n. Why? Because first
3:25:59
of all it takes big of n time to generate this and then it takes big of n time to find the first missing positive
3:26:06
integer. So we are satisfying on that aspect. And if we see space complexity
3:26:11
well apart from using couple of variables we are not using any additional space because all of these
3:26:17
things are being done on the in given input array nums. We are not creating an additional new array. This is a very
3:26:24
good time in space complexity and a great approach to solve this problem because if you see in this problem what
3:26:30
are the all the things we have been through. We first saw the brute force solution, then we saw the sorting
3:26:35
solution, then we saw a hashmap solution and then we saw the optimal solution. So
3:26:40
we actually went through four different approaches and every single time we
3:26:45
started to improve upon something and this is what any single interviewer
3:26:51
would want to see that how you have been able to do things and
3:26:57
that is why pay companies love asking this question.
3:27:03
So now let's move on to the coding.
3:27:09
So for the given input first we are going to check that whether one is present or not. If one is not present we
3:27:14
are simply going to return one as the answer. Okay. Now the logic we are going to
3:27:20
apply is that any single value that is not falling between our given range we are going to convert it to value number
3:27:27
one inside the given nums array. Now all we need to do is we will need to
3:27:32
go over the given input array where we have already changed the values with one
3:27:37
and anytime we identify the value is different different than one we will go to this array and change its subsequent
3:27:45
index location to a negative value. Okay, perfect. So now with this loop we have
3:27:52
been able to convert all the values to the negative value wherever we find a subsequent positive value any any value
3:27:58
apart from one. Okay. Now all we need to do is run a for loop from int i is equal to 1 to the last element and we simply
3:28:06
need to check that at any given position if we identify a positive value we are simply going to return that index
3:28:12
character and that is going to be the answer. Now we are also going to check for a couple of edge cases as well.
3:28:18
Somehow if we are not able to return the answer which means we have found the perfect sequence. So we will need to return the last value inside our uh
3:28:27
first missing positive integer which is going to be n + one. And this is the whole code. Let's try to
3:28:33
run this code. Okay, seems like our solution is working
3:28:39
as expected. Let's submit this code
3:28:44
and our code runs 100% faster than all the other solutions which means this is a great solution. And uh I will be
3:28:51
posting this in the comments so you can check it out from there. Thank you.
3:29:08
So now the next topic we are going to talk about is very closely associated with arrays. It's called sliding window.
3:29:14
Essentially, we are going to have a subset in the current array that we are going to slide across the array to
3:29:21
fulfill some conditions. Let's try to see a visual explanation before diving deeper into the more questions
3:29:28
associated with that. So at a conceptual level, sliding window is very
3:29:33
straightforward. Basically we have given a sort of an array and we are trying to
3:29:39
find a piece of information that is located somewhere within this given
3:29:44
entire spectrum of array but we don't know what. So it can be an example where
3:29:49
we are given to find some value associated with a subset of array. Let's say this array contains total n elements
3:29:56
and we are being told that find a subset k such that u essentially maybe they all
3:30:03
sum up to a target. Um so that can be an example or it can be like a smallest
3:30:09
substring or a largest substring that means something or that we need to find some value associated with that. So in
3:30:16
all of these cases let's say that if we are given an array and we are trying to find a subset of an array of size three
3:30:26
where for each of the subset basically we need to find that what is going to be the maximum sum of this subset. If we
3:30:33
take the brute force approach we would basically end up calculating every single possible uh different arrays or
3:30:39
different outcomes and we would have created bunch of different nested loops in order to achieve that. Now this is
3:30:45
very expensive. A better way to do it is that we can clearly define that this is going to be the window that we are going
3:30:52
to slide over in the existing array and this window is initially residing
3:30:57
between these two elements and let's say that sum of these three elements turns out to be 30. Let's say each of these
3:31:03
values are 10 10 and 10. Now next value we currently have is let's say five. So in this case instead of just recreating
3:31:10
all the calculations or reiterating over these two values because we already know that they are part of the window we can
3:31:17
just simply change the position of the window and now only include these three elements. And now all we need to do is
3:31:23
from the previous sum of the existing window we can just reduce whatever the
3:31:28
value this was. So 30 minus 10 because we eliminated this element from the window and then add this element. So +
3:31:36
5. So this sum is going to be 25 and we can say that okay this sums to 25. Then
3:31:41
same way for next window we can repeat the same operation and this is an example on how a changing window can
3:31:49
create some interesting results. Now there are some very popular questions associated with this and one of them is
3:31:57
my favorite question that is the best time to buy and sell stocks. So that
3:32:02
would be coming in uh in our most popular lead code problems that we would
3:32:07
be doing. So let's try to solidify our concept for the sliding window. Now
3:32:15
today we are going to do best time to buy and sell stocks lead code problem. This question has a very real life
3:32:21
practical application. That is why it is very famous amongst IT companies as an interview question. uh if we see some of
3:32:28
the companies where I want to work at who have already asked this question there are companies like Amazon, Microsoft, Facebook, Bloomberg, Google,
3:32:34
Goldman Sachs, Apple, Uber, Snapchat, Yahoo, Bite Dance, Door Dash, eBay,
3:32:41
Netflix and Reddit. So that's why I'm paying my utmost attention. I hope you also enjoy the video. So this is the
3:32:48
lead code easy problem and you can see that it has been one of the most liked problems on lead code. If we try to
3:32:54
understand the problem statement, b basically we are given an array called prices where any single uh value inside
3:33:00
this given array indicates the price of that particular stock and that on that particular day. Now we want to maximize
3:33:07
our profit by choosing a single day to buy the stock and choosing a different day to sell the stock sometime in the
3:33:13
future and our aim is to maximize our profit. So if we try to see it with an example, suppose this is the example
3:33:20
that we are given where we are given six different prices for a stock and we are told that we need to maximize the
3:33:25
profit. So I have drawn it on a graph over here. So it makes things more uh easy to understand and we know that at
3:33:32
any given position it shows that what is the price of that particular stock. So initially the stock price on first day
3:33:39
was price 7. Now on the second day the price fell down to price one. So we are not making any profit. we are actually
3:33:45
going down and we are losing the money. But if we see over here, so this day it's one and this day the price is five.
3:33:51
So if we see over here between these two days we actually made a profit of $4.
3:33:56
Again price fell next day to $3 and then again price rise to $6. So over here we
3:34:02
lost $2. Over here we again made some gain of $3. And at the end the price was
3:34:07
four. So over here again we lost $2. So the thing is if we just do it like this
3:34:13
we don't get the maximized profits. Why? Because we are only seeing that what is the difference between every single day.
3:34:19
But if we see that if we do something if we buy the stock on this particular day which means that we are buying the stock
3:34:25
when the stock price is at 1 and if we sell the price when the stock price at six. So which means if we sell when the
3:34:32
stock price is at six we can actually make a profit of $5.
3:34:37
This is the answer we need to return that this is the maximum profit we can make uh based on these stock prices. Let
3:34:43
me show you that what would be the brute force approach and then I'll show you that what would be the optimal approach.
3:34:50
So for the brute force approach one thing we can do is that we take every single position of a buy and sell price
3:34:57
for these given stocks which means that we make every single pair. So first of all we see that if we buy the stock at
3:35:03
price 7 and we sell at price 1 again we sell at price five again we sell at price three and so on and so forth. What
3:35:08
is the maximum profit we are getting and we will create a variable called profit and we will keep track that what is the
3:35:14
maximum number we have found so far. Once we are done with this value number seven we would ignore this case and then
3:35:19
again we will repeat the same thing with value number five. So we start buying uh so we start that our buy price is at
3:35:25
value number one and again we start checking all of the comparisons that what would be the profit and eventually
3:35:32
we would find a pair where buy value is one and sell value is actually six which means that we would gain profit of $5
3:35:38
and then we will return this as our answer like this solution would work as expected. We will get the desired
3:35:44
result. But the thing is this is not the most optim optimal approach. Why this is not the most optimal approach? Because
3:35:49
if we see uh the time complexity, the time complexity in this case is actually going to be big of n². Why n²? Because
3:35:56
for any single entry, we will have to take a look at every single entry in the remaining array and we will iterate this
3:36:03
process. So that is why it is a very timeconuming process and we need to find
3:36:08
a way to do something better and uh let me quickly show you that what would be the optimal solution in this case.
3:36:15
So for the optimal approach what we are going to do is we are actually going to see that uh when do we get the maximize
3:36:21
profit. We only get the maximize profit when we buy at the lowest value and we
3:36:26
sell at the highest value. So this is the logic we are going to apply over here that uh we are going to buy the
3:36:32
stock at the lowest value and we are going to sell the stock at the highest value. But thing is it is not as easy as
3:36:38
finding like the maximum value and the minimum value because in this case maximum value is actually seven and
3:36:44
minimum value is actually one. We don't need to get the difference of these two value because if we do that we will get an answer of six. But the thing is uh we
3:36:51
are actually dealing with stocks. So we can only buy stocks uh in the past which
3:36:57
means that if we decide to buy a stock over here we can only sell it afterwards. We can't sell it uh to some
3:37:03
value in the before. So that's why that is one thing we need to keep track of that we have to make sure that this
3:37:09
linear property of buying and selling is maintained in this case. So what we are going to do is we are going to have a
3:37:14
variable called buy and that is going to keep track of what is the minimum value we have stored so far and we are going
3:37:21
to see that at any given moment whatever the minimum buy value is if on that
3:37:26
particular day we try to sell a stock what is the profit we are getting. So let me quickly draw three variables over
3:37:32
here. So we are going to have three variables called buy, sell and profit. Now first of all we are at this position
3:37:37
number seven which means that we are buying the stock at 7 and we can't do anything about it because we don't have any way to sell it. Uh so we will start
3:37:45
with the second position. So now on the second day the stock price fell down to one which means that if we can we have
3:37:51
already bought this stock at value number seven. If we try to sell it at value number one it really does not give
3:37:57
much progress. But one thing we can do over here is that because today the stock price is actually low we can
3:38:04
reduce that whatever the buying price is from 7 to 1. So we will do that. So now the buy price is actually one and uh we
3:38:11
are not selling anything or we are not doing anything again. Now the next day the price is price of the stock is five.
3:38:18
So we'll try to do that. Okay, what is the 5 - 1 which is the minimum price we have bought stock so far and 5 - 1 is
3:38:24
actually four which is the maximum profit we have made so far and we don't need to update this buy value because we
3:38:30
have already bought it at a lower price than whatever the current price of the stock is. Now we will move on to the
3:38:35
next value. So next value the stock price is actually three which means three is still greater than value number
3:38:41
one which means we don't need to update this value number three but we will have to check that whether we are making any
3:38:46
greater profit or not. So again we will do 3 minus whatever this buy value is. The buy value is 1. So 3 min - 1. So the
3:38:52
pro current profit we make is actually two. But the thing is two is actually less than four which means we can we don't need to update the profit we have
3:38:58
made so far. Now again we will ignore this case. We will move on to the next value. So the next value the stock price
3:39:04
is actually at six. So stock price is now at six. And now again we will do 6 - 1. So 6 - 1 uh selling price would be
3:39:11
actually five. And because this is five and this profit is actually greater than whatever profit we have achieved. so
3:39:17
far. So the current maximum profit we have made so far is five. Now again the stock price is at four. So again the
3:39:23
selling price on this day would be four and we don't need to update the buying price because the buying price is already at one which is lower than four.
3:39:30
And now we will do 4 minus 1. So 4 minus one if we do we still make profit but
3:39:35
this profit is only $3. And $3 is actually less than whatever the maximum profit we have made so far. Now we are
3:39:41
at the end of our loop and now we don't have any more values to iterate over inside the given array which means
3:39:46
whatever the result we have start stored inside the maximum profit variable we will just return that and in this case
3:39:52
we will return answer as five and this answer would work perfectly fine. This is like the most desired answer we need.
3:39:59
If we see the time and space complexity in this case the time complexity is actually big of n. Why bigo of n?
3:40:04
Because notice that we are completing everything in a single iteration and uh in terms of space complexity for the
3:40:11
space complexity we are not actually using any additional space apart from storing couple of variables. So that's
3:40:16
why space is also constant. So that's why this is a very good approach. We are solving this in big of n and big of n
3:40:22
time and big of one space complexity.
3:40:28
So first of all we are going to initialize a variable called min and we are going to give it the first value of
3:40:34
the given price. This uh we are going to create a variable called profit to note
3:40:39
down the maximum profit we can achieve and initially we are going to mark it as zero and then we will update the value inside our loop. So now we are going to
3:40:46
run a for loop across the given array. Now inside the given loop first of all we will check that whether we need to
3:40:52
update the value of min or not. So we will check that if the current min value is less than whatever the value of i is
3:40:58
then we will update the value of min and also we will check that whether the
3:41:03
current profit we can make by selling the stock on that particular day comparing with the min value. uh we will
3:41:09
choose the maximum profit we can and once this loop ends we simply need
3:41:14
to return the whatever value we have stored in the profit variable.
3:41:23
Let's try to run this code. Okay, seems like our code is working as
3:41:28
expected. Let's submit it. And our code is actually pretty efficient. It runs faster than lot of
3:41:35
other solutions. And I will be posting this code in the comments so you can check it out from there. Thank you.
3:41:46
Hello friends, hope you are having a fantastic day today. So once again we are going to do an awesome lead code problem that has been asked at tons of
3:41:52
companies. So without any delay, let's get started. So the lead code problem we are going to solve is called permutations in a string. And we can see
3:41:59
that this is a lead code medium problem and also extremely well-like problem on lead code. The problem statement is very
3:42:06
straightforward that we are given two strings s_ub_1 and s_sub_2. Now we need to check that if any of the permutation
3:42:12
of s_ub_1 is present inside the s_2 string then we need to return true. If that is not the case we need to return
3:42:18
false. Now let's try to see see this with an example. Say for an example we are given s_ub_1 is equal to value a and
3:42:26
b and we are given a string s_ub_2. Now there can be two permutations and
3:42:31
combination of a and b. it's a and b itself or either b and a. Now we can see that in this string s2 b a is actually
3:42:39
present. So because it is present we can actually return this as true saying that a permutation of a b or string one is
3:42:47
actually present inside the string two. Now let's take one more example. uh in this case we have BA as partial
3:42:56
permutation of the string one but we does not have anything like C or we have
3:43:01
in this case we have a C but there is an X in between so we do not have any direct permutation of string one present
3:43:09
inside the string two. So in this case we can return false. Now even though we have a B and C all three present inside
3:43:17
the string two but they are not present together. So that is the main problem. So now let's see that how can we
3:43:23
actually solve this problem and the number one approach is very simple brute force approach. So for the brute force
3:43:29
approach what we can do is we can take string one suppose the values are a b c and then we can take string two suppose
3:43:36
the given values are once again b a x c d z something like this. So we can take
3:43:42
every single possible permutations of s1 and then we can check check that whether those are in any given moment present
3:43:49
inside the string two or not. So this is going to be very inefficient approach. So we need to do something better. Now
3:43:56
the question is in any given case suppose the string one is a b c then
3:44:03
what are the different permutations and combinations possible in either case you can notice that
3:44:09
instead of keeping track of all of these permutations and combinations we can say that currently for the string one we
3:44:17
actually have three different characters and the frequency of each of the these
3:44:22
three characters is actually one time. So we have a present one time, b present
3:44:28
one time and c present one time. So at any given moment inside the string two
3:44:33
if we identify that suppose string two is let's say that x b a c d z something
3:44:40
like this and if we identify that amongst any given moment we can identify
3:44:46
these three occurring in any subsequence in the same amount of frequency. So I'm
3:44:52
not talking about order that A has to come before B has to come before C. I'm talking about the frequency that at any
3:44:58
given moment we wants to check that whether all three a b and c are present in the same number of uh occurrences
3:45:06
which we can see over here that if we take a look at this portion we can actually see that we can also make
3:45:12
another frequency map that contains once again characters A, B and C and each
3:45:17
occur one time. So because there is a match in this regard we can actually say that this string one is actually a
3:45:25
present inside the string two as one of the permutations or combinations. So this is the approach we are going to
3:45:30
use. Now in order to use this approach we actually need two things. Number one
3:45:36
item we need is that we need a way to create a frequency map to contain that
3:45:42
how many times any single character is present inside the given string one.
3:45:47
Then we need to create the window of that exact same size and then iterate
3:45:52
over every single possible windows of the string two. And once we do that, all
3:45:58
we need to do is just compare two different frequency maps. So what are
3:46:03
the efficient ways for us to compare frequency maps and create sequ frequency maps? Well, there are actually two ways.
3:46:09
So number one way is that we can actually use a hashmap because in the hashmap we know that it is a key value
3:46:14
based pair data structure. So as a key we can set up the character and as its
3:46:20
subsequent value we can set up the frequency. So once we have the hashmap or frequency map for string one we can
3:46:28
do that and same way the existing window we have for string two we can actually
3:46:33
create a very similar frequency map uh for the string two as well. So that is option number one. The option number two
3:46:39
is that we actually create an array with 26 characters and we create two arrays.
3:46:46
So one array is for string one, one array is for string two for that specific window. And let's assume that
3:46:51
in string one uh the value is a b c. So we can mark a bc as 111 and for rest of
3:46:58
the characters we can mark them as zero. And this can be uh also an efficient way for us to check that what is the
3:47:04
frequency and how many uh times it is present. So same way for S_2 we can also
3:47:09
create uh an array. So both ways will would yield the same uh space
3:47:15
complexity. So what I'm going to do is uh in the example I will explain it to you using hashmap but in the code we
3:47:21
will use the array method. Okay. Now let's try to understand the approach I'm suggesting using couple of examples. So
3:47:28
suppose we are given our string map is equal to value a b a and we are given
3:47:33
our string 2 as the values a b c d e f e
3:47:38
x then a a b something like this. Okay. Now we know that what is the approach we
3:47:45
are going to do for string one. We will have to create a hashmap. So let's quickly create a hashmap. The idea is
3:47:51
that string one hashmap is going to look very simple that it only contains three characters that are a and sorry only two
3:47:59
characters a and b. Now a is present two times and b is present one time. Now we have the hashmap for string one. Now for
3:48:06
the string two what we are going to do is that we are going to create an exact
3:48:11
same size window and then we are going to keep sliding that window over from left to right and using that approach we
3:48:20
would be able to solve this problem very easily. So let's let me tell you what I'm what we are trying to do. So
3:48:26
initially the string two does not have a hashmap. Uh so let's create a a frequency map for string two as well.
3:48:32
Okay. And I'm marking three values. Uh so now let's see okay currently uh this
3:48:38
one does not have anything. So we are going to consider these three values as our first window. Now we are going to
3:48:45
create a frequency map and the idea is that we can keep on comparing the two frequency maps or if you don't want to
3:48:52
create two maps we you can actually start deducting values as well but in either case you will have to remember that what was the original state. Okay
3:48:59
so that's why for our simplicity I'm creating two maps. So now for this A we
3:49:04
have this A and it is occurring once. Once again we have this B it is also occurring once and then once we have C
3:49:11
that is also occurring once. But if we compare these two then uh we can see that A and B is partially there but C
3:49:19
should not be there and uh we are still missing one A. Okay. So in this case this is not the correct approach. So now
3:49:26
we will have to migrate our window one step forward. Which means previously we were considering this ABC. So now we
3:49:32
will get rid of this A and we will treat as if this A is currently no longer needed and now we are going to be
3:49:38
dealing with this particular window. Now the thing is when we are dealing with this window the question is do we need
3:49:43
to create another same window for this new portion? The answer is no. We can actually do something very simple. The
3:49:50
idea is that whatever the value was present over here, we can actually get rid of that value because we are moving
3:49:56
to the next step inside our uh sliding window and then whatever the new value is, we can simply add that new value to
3:50:03
the hashmap. So now we are going to get rid of a and we are going to add another value d and we are going to mark its
3:50:09
frequency. So d is also present once but once again this window also does not yield us the correct result and these
3:50:16
two are still not equal. Okay. So now we will have to consider this window. So once again we will keep on repeating the
3:50:21
same process. We will get rid of B. Once again we will get rid of B. We will include value E again. So now E is
3:50:28
present one time. But also this window does not work as well. So now we are also going to get rid of this value
3:50:33
number C. Now C is no longer present. Uh so but now we are going to include value number X. So X is present one times. But
3:50:41
once again this is also not correct. So we will get rid of D and we will have this window to consider. So now we are
3:50:46
going to get rid of D and we are once again going to add value number A one times. Now once again this is not the
3:50:52
correct approach. So we will once again get rid of value number D sorry value number E and the new value is A. So
3:50:59
because new value is A. A is already present which means we do not have to add A again. So we can just mark
3:51:06
increase the value of A second time. Now currently we are considering this window but this is also not the correct window.
3:51:12
So we will also get rid of this one. we will kick x out and then we will add value number b. So adding value number b
3:51:20
would allow us to add one more value b inside over here. And now this is our final window. But in the final window we
3:51:26
can see that both string one hashmap and string two hashmap are same. The
3:51:32
frequency of character occurring is exactly same. Which means we have found our optimal solution and we have we can
3:51:38
say that currently one of the permutation of string one is actually present inside string two. So we can
3:51:44
return true as the answer in this case. And in case say for an example this one
3:51:49
was not B and this one was something else like character D. So the moment we reach to this value and we have a string
3:51:56
that looks like D1 something like this. Then there is no longer a window
3:52:02
possible for us to move forward which means we have exhausted every single possibility in string 2. Still we did
3:52:08
not find the same set of frequency of character present inside the string one. which means we can simply return false
3:52:15
in that case and this is the whole approach. So this would be the optimal solution. If we see time and trace
3:52:20
complexity in this case the time complexity is very simple. It's going to be big of n because number one in order
3:52:26
to create this hashmap it takes us big of n time and then using a slider sliding window we simply have to iterate
3:52:32
over this given array. So this is also big of n in terms of space complexity. So this can be big of one. Why? Because
3:52:40
we know that there are only 26 characters inside the alphabet. We are not dealing with any special characters
3:52:45
or any extra elements which means there is only a finite number of characters we can store inside our uh hashmap or
3:52:52
frequency maps. So that's why space complexity is going to be one. So this is a very good time and space complexity
3:52:59
which yields us very good results. So now let's quickly see the coding solution for this one. So first of all
3:53:04
we are going to check that if the given string one is actually greater than string two which means we can directly
3:53:10
return false. If that is not the case we are going to initialize two arrays with the size 26 which we are going to use as
3:53:17
frequency maps. Then we are going to initialize the frequency map for the string one and also for the first window
3:53:23
of string two and the first window of string two is going to be the length of a string one. Okay. then we simply have
3:53:30
to slide the window through uh s_ub_2 and compare it with the frequency map of
3:53:36
string one. If both match then we can simply return true. If that does not match, we are going to keep on updating
3:53:43
the window of the given string. Which means we are going to drop off the left side of the element and we are going to
3:53:49
add the right side of the element and then we can s once again keep on repeating the same process until the
3:53:55
very last window. If we do find that there is a match then we can simply return true. At any given moment we find
3:54:02
that uh we are able to reach to the very end then we can simply return false. And we are creating a helper function to
3:54:09
compare the frequency of two maps which is going to be just running for loops across both the arrays and check that at
3:54:15
any given moment whether the the frequency is deviating away from a
3:54:21
single character or not and then we can simply break out of that loop. Okay. So let's try to run this code.
3:54:29
Okay, seems like our solution is working as expected. Let's submit this code.
3:54:35
And our code runs extremely fast in terms of time complexity and also very efficiently in terms of space
3:54:41
complexity. So you can find this code in our GitHub repository and the link is in the description. Thank you.
3:54:54
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do longest repeating character
3:55:01
replacement lead code problem that contains very important properties related to string based problems. If we
3:55:07
see the companies where I want to get a job and that have already asked this question there are companies like Google, Amazon, Uber, Adobe, Facebook,
3:55:14
Apple, Bloomberg and Microsoft. So some of the top tier IT companies. So that's why I am paying my utmost attention. I
3:55:20
hope you also enjoy the video. So this is a lead code medium problem
3:55:26
and basically we are given a string s and we are given an integer k. Now we are told that inside this given string s
3:55:33
we can replace any character with any other character uh in the English language and we can repeat this
3:55:39
operation k times. Now after repeating this operation, what is the main purpose of this question is that we need to
3:55:46
return the length of the longest substring that contains the same letter by doing this replace activity and we
3:55:53
need to return that length. Okay. So now we will try to understand this problem with this example. So suppose we are
3:55:58
given our s is equal to a b a b and we are told that k is equal to two which
3:56:04
means we can replace any two character with whatever two characters we want. So in this case we have two options. Either we replace these two b's with value
3:56:10
number a then we will get a string that looks like a a a or we can replace these
3:56:15
two a's with the letter b and then we will get string. Our concern is we don't
3:56:21
care what is the value of the string. Our aim is to find the longest uh substring that contains all the repeated
3:56:28
character and we need to find the length of it. In both the cases the length of these two is actually four and this
3:56:34
would be the answer we need to return. So this is what the problem is asking us to do. Let's take one more example to
3:56:40
make our understanding more uh clear. So suppose our given S is equal to HP HPH.
3:56:47
If this is the case and our given K is equal to two again in this case. So now
3:56:52
if we see the options we have we can replace like these two P's with the value H. Uh so that will give us a
3:56:59
string like HH H. And so if we see the longest substring that contains the same
3:57:04
letter, the length in this case becomes five. Uh second option we have is that we choose any two h value suppose these
3:57:11
two and we replace it with value number p. If we do that we will get a substring that looks like this. So in this case if
3:57:18
we see that what is the longest length of the subsequence that contains the same letter. It's actually four. So this
3:57:24
is four and this is five and we need to return the longest. So that's why this is the most optimal way to approach this
3:57:30
problem in this case where we we are going to replace these two P values with the eleator H and we don't do this P
3:57:37
operation. So there are few ways to solve this problem and there is also brute force way to solve this problem.
3:57:42
So first I'll show you the brute force way and then we will see that what would be the optimized approach. First of all
3:57:48
we identify that what is the thing that we want to find. We want to find a substring and then we want to replace
3:57:54
the characters and then we want to find a substring that contains the longest length with the same characters. Right?
3:58:00
So first approach we can take in the brute force is that we take every single substring that is possible. So even if
3:58:06
we just see that substrings that starts at a we will get substrings like a a b a
3:58:11
b a and a b a b something like this. Again if we see substring that starts
3:58:16
with b we will get b a b a b and so on and so forth. So we would end up with bunch of different substrings. Then we
3:58:23
will start this replace operation on all the substrings and eventually we would find some substring that will look like
3:58:29
this a a a or this bb. And in any case we would be able to
3:58:35
return the length as four like okay this solution would work and we will get the desired result. But there are a lot of
3:58:41
issues with that. Even if we just see that for a single character, we end up with like so many substrings and we
3:58:48
still have more substrings to go through. So this is a very inefficient approach and we should avoid doing it at
3:58:53
all cost. Okay, before we come up with the optimal
3:58:58
solution, first of all, we will have to identify that what is our need. Our need in this case is that we are given this
3:59:04
string and we are told that we can replace any two characters inside this given string with any other characters
3:59:10
because K is equal to two. Now we need to find a substring where all the characters contains the same value and
3:59:17
because they contains the same value we need to return the length of it. So first of all we will have to identify
3:59:22
that what is the substring where we can actually create all the characters of the same length. So first of all let's
3:59:28
see that can we apply this thing on on this whole substring for this entire string of all the five characters and
3:59:35
this given k is equal to two. So first of all we will try to identify that what is the number of occurrences on of every
3:59:41
single character. So A occurs two times B occurs once C occurs once and D also
3:59:47
occurs one. So which means that A because A occurs most of the time our logical or rational conclusion is to
3:59:54
create a substring where all the characters are a because in that case we will actually have one additional
3:59:59
character. If we try to create all the characters with l with value B, C or D,
4:00:05
obviously we are always going to fall short by one character because the value of A actually appears twice. Which means
4:00:12
these three things they have less significance compared to this A because A is the most repeating character. And
4:00:18
why I'm putting so much emphasis on most repeating character because this along
4:00:24
with this K and the length of the string or substring defines that whether any
4:00:29
substring we can convert it to all the repeating characters or not. Let me show you how. Suppose in this case we
4:00:35
consider all these five characters. Even if we replace any two characters in this
4:00:41
case we have three characters to replace from. If we replace any two characters, no matter what happens, we won't be able
4:00:47
to create a substring where all the five values are actually a a a. Why? Because
4:00:53
we only have the option to replace two elements and there are three different elements that contains different values.
4:00:59
So how come how we come up with this value that there are three different elements that contains different value
4:01:05
than a? Well, what we did was we took the length. So length in this case for this substring is five. So we took the
4:01:12
length of this substring minus we subtracted the most occurred character.
4:01:18
So most occurred character in this case is a. So length 5 minus a 2 and this we
4:01:24
get three. So at any case this value if that is greater than or equal to this
4:01:30
value number k which means that this particular substring we cannot do anything about it. we cannot convert
4:01:36
into a valid or legitimate substring where all the values contains the same same character. But if we just shorten
4:01:44
our search, if we try to search in this these four characters, okay, now what is
4:01:49
the breakdown of uh the number of occurrences of every single character? Well, A still occurs twice, B occurs
4:01:55
once, C occurs once, but D is not appearing. So, we ignore this one. Now in this case the length of this is equal
4:02:03
actually four which means that if we apply the same formula that length minus
4:02:08
whatever the maximum occurred value. So maximum occurred value is still a which means that we do 4 minus 2. Uh so 4 - 2
4:02:16
is 2 and this 2 is actually equal to whatever the value of k is because this
4:02:22
is equal to k and uh in this case we can define that for this particular
4:02:27
substring we can actually convert it to all the characters being same by using this replace function and if we just
4:02:34
replace this value b and c we will get actually a substring that is all the a's and this is the answer. So basically
4:02:41
this is the critical part. Now remember that in order to generate this what are the things we needed? We actually needed
4:02:48
that what is the current length of the subsequence that we are following or what is the length of the substring that
4:02:53
we are doing. We actually need to know that what is the maximum occurrence of any particular character in any given
4:03:00
subsequence and we also needed that what is the value of K. Based on it we were
4:03:05
able to identify that whether any subsequence can it be converted to having all the characters to have the
4:03:11
same value or not. And based on this concept, so formula we can create is
4:03:16
that uh a valid subsequence is a subsequence where the length of the
4:03:22
subsequence minus the most occurred uh character. If this if this one is
4:03:28
actually less than or equal to whatever the value of k is. If this is true then
4:03:33
we can say that this is a valid substring and the length whatever the length of this particular substring is
4:03:40
uh that is also the length of the substring which which contains the most repeated characters. Let's see it with
4:03:47
an example.
4:03:52
Okay, suppose this is the example that we are given and we want to solve this one. First of all, we are going to see that what is the formula that we have to
4:03:59
use. Well, the formula we have to use is that for any subsequence to be valid, what we are going to do is we are going
4:04:04
to do length minus whatever the max occurrence in that particular subsequence and we will see that if that
4:04:11
value if that is less than or equal to K. If that is less than or equal to K whatever the length is, we can treat it
4:04:17
as our answer and whatever the maximum answer we find so far we will con conclude it as our solution. We already
4:04:24
know this formula. Now we need to see that how can we implement that. Basically uh we are going to use a
4:04:29
sliding window plus two pointer solution and inside this solution what we are going to do is we are going to have two
4:04:35
variables called left and right to be initialized at the first position. Uh we are going to update the right value to
4:04:42
the next element. Then we will check that whether the substring is valid or not. If the substring is valid we will
4:04:48
calculate that what is the answer. We will update the answer. Again we will move the right value and again we will
4:04:54
move the right value. So again we will move the right value until the point when the substring is not valid. The
4:04:59
moment the substring is not valid we can conclude that now we need to shrink our substring. So basically suppose the r is
4:05:06
now at this position we will have to update the value of left. So we will ignore this element and we will move our
4:05:12
left value over here and then subsequently we will keep moving on and every single time we will keep track
4:05:18
that what is the maximum answer we have found so far which is the longest repeated character sub substring uh the
4:05:25
length of it and whenever the r reaches at the end of the list or at the end of this string we can conclude that
4:05:32
whatever the value we have stored in the answer we can return it as as the answer. So now because we are using this
4:05:37
two-pointer approach we know that uh at any given moment what are the things we need? Well we need couple of things. Uh
4:05:43
first thing we need is we need this length. So length we can identify based on the difference between this left
4:05:49
pointer and right pointer. That gives us the length of the current substring. Now we need to know that what is the maximum
4:05:54
occurrence at any given moment of any particular element. So we don't know that right? So what we can do is we can
4:06:01
actually create an array of size 26. uh so one for every single character in the
4:06:06
English language because we know that there are only 26 characters and whenever we find any value on the right
4:06:13
side we will add that value to our array or if we move any character on the left
4:06:19
side we will reduce that value from our array. So at any given moment we would always know that what is the maximum
4:06:25
value we have at uh any given position and let's see by an example that how we
4:06:30
will complete this operation. So let me quickly show you an example that how we will iterate over for this given example. Let me clean this up a bit.
4:06:38
So initially our left value and right value are located at these two positions. We are also going to have an
4:06:44
array to store the maximum occurrence of any single element. So currently I'm just showing you the elements that are
4:06:49
coming in. But that that is the idea that we will keep in mind. So first of
4:06:54
all currently the value is P. So we will add P over here and we will not notice that okay the occurrence of P is one
4:07:01
time just this is for understanding purposes when we do the code it would be slightly different and I will explain it
4:07:06
to you when we when we would be coding. Uh now uh so far this list has to be valid because there is only one
4:07:12
character right. Uh now we will update the value of our R. So this is X and X is also present one times. Uh now we
4:07:19
will see so current length of this uh string. So now R is located over here.
4:07:26
Okay, so current length is uh actually two and what is the K value? K value is
4:07:32
also two because that is constant. So that won't change. And what is the maximum occurrence of any character so
4:07:38
far? So maximum occurrence is still one as we can see over here. So maximum occurrence is one. So if we apply this
4:07:43
formula 2 - 1 so 2 - 1 is actually one and one is less than or equal to value
4:07:49
of k. So that is true. So because this is true we can say that the length of at least two uh characters uh can can be
4:07:56
part of the answer. So we will mention that in the answer. Now again we will update the value of r. So now r comes
4:08:03
over here. Because r comes over here we will update the value of q over here and we know that it occurs one time again.
4:08:09
So the length so the current length is actually three and uh the maximum character is still one. So we will do 3
4:08:16
minus 1. So 3 - 1 is again 2. 2 is still less than or equal to value of k. So this is also true. Because this is true,
4:08:22
the current length can be part of the answer. So we'll update our answer to have the value three. Now we will again
4:08:28
update the value of our r. So now r will go over here and this is x. So for x
4:08:33
value we already have one uh as its occurrence. Now x has the occurrence two times. So we will update the occurrence
4:08:40
of maximum number over here called two times. Uh the length also increases. So length will become four. Now again we
4:08:47
will try to see that what happens with our equation. So we will do 4 min - 2. So 4 minus 2 this is 2. 2 is still less
4:08:54
than or equal to k which is 2 which means that we can update the answer to the value four. We will update the
4:09:01
answer to be four. Now again we will update the value of our r. Now r moves one value to the right. Now this is y. Y
4:09:08
is occurring one times. Uh now the current length is five and the maximum
4:09:14
value we have is x which is 2. So, so far we are good. Uh, now we will try to do 5 - 2. So, 5 - 2 is actually three
4:09:21
which is greater than k which means that this condition is not satisfied. So, because this condition is not satisfied,
4:09:27
what we need to do is we need to update the left element. So, we will update the left element over here. So, now left
4:09:34
comes at this place. But because we are updating the left element, we will also have to remove this one p over here. So,
4:09:39
we will uh remove p from here. And now uh we will update the values. So now length will become four. Again maximum
4:09:46
occurrence is still 2. So 4 - 2 that is 2. 2 is still less than or equal to k
4:09:52
which is good. So so far we are good. Now again we will update the value of our r. So now r comes at this place.
4:09:58
Because r comes at this place the occurrence of x comes to three. Now because this comes to three we will
4:10:03
update the value of maximum occurrence to be three and we will update the length to be five. Now we'll do 5 - 3. 5
4:10:09
- 3 is 2. 2 is still less than or equal to k. So because uh two is still less than or equal to k we can we can update
4:10:16
our answer as well to the whatever length we have found which is five. So we will update our answer to be five.
4:10:22
Now again we will update the value of our r. r comes over here. Now this is a a we don't have any entry. So we will
4:10:28
add an entry for a and we will call it as one. Now in this case the length is six. Length is six but maximum number of
4:10:34
occurrence of x is still three. Which means that now we can do is uh 6 - 3. So if we do 6 - 3, 6 - 3 is equal to 3. 3x
4:10:43
is actually greater than k which means this condition is not satisfied. So now we will have to update the value of our l over here. So now we will get rid of 1
4:10:50
x. Uh so because we are getting rid of 1x the current maximum occurrence we have so far is two. Okay. Now our left
4:10:57
is located at this position. Now the length is five and uh the
4:11:04
maximum we can make maximum occurrence is two. So again 5 - 2 is still three which is greater than K. So again we
4:11:10
will have to update the value of our left. So now this time left comes over here and we will ignore this Q which
4:11:15
means the value of Q becomes zero. So I I'll just remove that entry. Now again this time the length is actually four
4:11:22
and the maximum occurrence is 2. So 4 - 2 is still 2 which is uh which is actually less than or equal to K. So
4:11:28
because this is less than or equal to K. We know that okay length four is can be our answer but our answer is already
4:11:34
five. So there is no point in updating length to be four. Okay. Uh next we what we are going to do is now this time we
4:11:40
will have to update the value r. So when we update the value r we actually re reach to the end of the string and
4:11:47
because we reach to the end of the string whatever the value we have stored in the answer we can return it as our answer. So in this case the answer is
4:11:53
going to be five from this sequence and we can mention that after doing two word replacement the maximum substring we can
4:12:00
make that contains all the same characters inside this given original string is actually of length five and
4:12:05
that is the solution. If we see the time and space complexity for this one the time complexity will actually be big of
4:12:11
n where n is the number of characters that are present inside given s. Uh now you will think that okay in order for us
4:12:18
to find the maximum occurrence actually we will have to iterate over this entire array and it might takes like there are
4:12:23
26 entries so we might have to do this work 26 times. The thing is we are actually going to use a clever trick
4:12:28
over here. What we are going to do is at any moment we update our right pointer at that moment only we are going to
4:12:35
update our maximum occurrence because remember our maximum occurrence can only increase when we update the value of our
4:12:42
right. Whenever we update the value of our left, we essentially decrease the whatever the maximum count we have.
4:12:47
Which means that our maximum count is never going to go high. So that's why by using this clever trick, we can actually
4:12:53
reduce the time complexity to big go of 26 * n to only big of n. And you will
4:12:59
see it in the coding. Also in terms of space complexity, we can conclude this actually two times. We can either
4:13:05
conclude this to be big of 26 because we are storing an array of 26 characters or
4:13:11
we can consider this as big of one or constant constant space because this 26 is a finite number. This not this is not
4:13:17
an infinite number. So that is why uh depends on your pro interviewer how he wants to treat it and uh that that way
4:13:24
you can take it forward. Now let's move on towards coding.
4:13:31
First of all, we are going to create an integer array to store the occurrences and we are going to name it as
4:13:36
occurrence. Now we will create few variables. So first of all we will create variable
4:13:41
left and right and we will initialize it to value number zero. Now we will create a variable called
4:13:47
answer and we will initialize it to zero as well. Also we will initialize a variable
4:13:54
called maximum occurrence. Now we will run a for loop on all the characters of given string.
4:14:02
So first of all we will calculate that whether we need to update the maximum occurrence or not.
4:14:10
So now we will check that whether the current substring if that is valid substring or not. So we are going to use
4:14:16
an if condition. First of all we are going to check that whether the length. So in that this case length is going to be right minus left plus one.
4:14:27
So if the length minus whatever the maximum occurrence is
4:14:33
if that is greater than k which means that uh if that is greater than k which means that the current substring is not
4:14:39
valid. If that is not valid we will have to update the value of left variable
4:14:47
and we will also have to decrement the value that is located at uh current left counter on the given string.
4:14:55
Once that is done for every single update we will have to check that whether our answer is the longest string
4:15:01
or not. So we will check that whether what is the value of our answer. That should be it. So after this loop
4:15:08
ends basically we should have our answer stored in the answer variable. So we can simply return that.
4:15:14
Let's try to run this code. This should have an occurrence.
4:15:23
Okay. Okay, seems like our solution is working as expected. Let's submit this code.
4:15:28
Oh, our solution is not working.
4:15:33
Oh, we need to decrement the value first before we
4:15:39
update this left pointer. So, let's try to run the code again.
4:15:47
Okay, let's submit it again. Seems like our solution is working as expected.
4:16:00
Hello friends, we are not employed by fang companies of lead coding till we get there. Today we are going to do
4:16:05
longest substring without a repeating character lead code problem and this is actually number three problem in the
4:16:11
lead code and also very popular problem as you can see the number of companies that have already asked this problem. So
4:16:16
if I just check the companies where I want to get a job and I have already asked this question. There are companies like Amazon, Microsoft, Facebook,
4:16:23
Bloomberg, Apple, Google, Spotify, Uber, Goldman Sachs, Yahoo, Walmart, eBay,
4:16:30
Lyft, Dance, Morgan Stanley and PTM. So that's why I am paying my utmost attention to
4:16:36
solve this problem. I hope you also enjoy the video. So this is a lead code medium problem
4:16:43
and also one of the most liked problems on lead code. Basically we are given a string s and we need to find the length
4:16:49
of the longest substring without a repeating character inside this given string. So suppose in this example we
4:16:56
are given a string like this. And in this case if we check that what is the longest substring without a repeating
4:17:03
character that is this one a b c and the length of this is three. We can also
4:17:08
conclude this one as well. this as also length of three and uh we can return either of them but the answer in this
4:17:15
case we are going to return is actually three. Let's see that what would be the different approaches to solve this problem.
4:17:21
So suppose this is the input that we are given and let's see that how can we solve this in a brute force manner.
4:17:26
Well, the ba most basic idea is that we can take this input and take every
4:17:32
single substring that is possible and then check on all of those substrings that whether there are any repeating
4:17:38
characters or not and whichever the substring with the longest length we found without any repeating characters
4:17:45
we will just present it as an answer. So if I just show you by an example in this case the number of substrings we can
4:17:51
make is okay let's start from this a. So from this A we can make a substring of A. We can make a substring A B we can
4:17:57
make a substring A B A. We can make a substring A B A T dot dot dot and so on and so forth. We can make all of these
4:18:03
substring. Next substring we will make starting from this value number B. So from B we can make B b a B A T B A T M
4:18:13
and so on and so forth. So in this case the longest substring we would be able to make is actually this uh one b a tm
4:18:21
that is of length four and this is the answer in our case. So even if we use the brute force approach eventually we
4:18:28
would have found this uh substring by comparing all of the bunch of different substrings that we will we would have
4:18:34
created and then we can we would have returned four in this case. But what is the issue with this approach? Well, the
4:18:40
issue is actually quite trivial that we are actually doing lot of unnecessary work and we are trying to find lot of
4:18:46
different substrings. Even if we just see the time and space complexity in this class, the time complexity is actually going to be big of n cube. Why
4:18:52
n cube? Because we are going to do n square work uh to find all the
4:18:57
substrings and then we will have to do n work for every single one of them to find that whether there exist any
4:19:03
repeating character or not. So this is a really bad approach. Let's see that what is the improvement we can make.
4:19:09
To optimally solve this problem, we are going to use very important concept called sliding window and in addition
4:19:15
with two pointer. What we are going to do is we are going to have two pointers called left and right. And these left
4:19:20
and right pointers, we are going to have them to follow a very important property and that property is that between these
4:19:27
values of left and right all the elements has to be unique. If at any moment we encounter that there is a
4:19:33
duplicate entry which means that we will update the value of L to the point where the duplicate entry is mitigated or it's
4:19:41
eliminated and then we will again keep on progressing with this right pointer. Let me quickly show you how we are going
4:19:46
to do that. So first of all left and right both are going to start at the same position. Now we are going to make
4:19:52
our right pointer move to the next element until the point where we find a place that is actually repeating. So we
4:20:01
are now our right pointer is at this position our left pointer is at this position. So so far we have two elements
4:20:07
in our substring and both are unique. So because both are unique we are good go good good up until to this point also at
4:20:13
the same time we are going to have an answer variable where we are going to store the length of the maximum uh
4:20:19
substring we were able to find with all the unique characters. So so far initially this value was one but now we
4:20:25
have found that there are actually two elements for this substring that has all the unique elements so far. Now we now
4:20:32
we are going to update the value of our right pointer again. So right pointer will come over here. Now again right
4:20:37
pointer is here but at this point okay we need to check that okay amongst this a and b does a exist somewhere and we
4:20:44
know that a exist over here. Now you will quickly ask me that okay in this case since we only had two elements and
4:20:51
we were comparing this a it was really easy for us to identify. What if we had like 10 elements like this and then we
4:20:56
are comparing this a and we need to check that whether at all these 10 positions does this a exist or not and
4:21:02
that would be make things really inefficient and that would be big of n square time complexity. So what we are
4:21:07
going to do is we are going to have a visited hash set and inside this visited hash set we are going to store all the
4:21:14
characters we have found so far between L and R and we are going to keep on adding until the point we find a
4:21:20
repeating character. So initially this only had the value A when we are at this point then we added a B. So so far
4:21:27
inside our hash set we actually have a and b and now when this r po pointer comes at this position a first of all
4:21:33
we'll check that whether a exist or not and we realize that okay a exist inside this hash set which means that amongst
4:21:39
this substring we cannot add this value a because a exist over here. So now what we are going to do is we are going to
4:21:46
remove a from this our set and we are also going to update our left pointer to remove this value a. So okay we ignore
4:21:54
this a and now our left pointer is at this position. Our right pointer is at this position. So so far the values are
4:22:00
b and a and now we are again going to add this value number a over here because this right pointer is here.
4:22:05
Okay. Uh what is the length so far? So the length is still two. So because length is two we are not going to update
4:22:11
in our answer because in our answer the length is also two. Now we are going to update our right pointer to come to the
4:22:16
next next element. And when we update the right pointer it comes over here. So this t does not exist inside our hash
4:22:22
set. So we will add entry t over here and our uh we will update our answer as well. So now the our answer becomes
4:22:29
three. Now again we will uh update our right pointer to come to come over here.
4:22:34
So when the right pointer comes over here we will have an entry m. So again
4:22:40
we will add the value m over here inside our hash set because it does not exist before. And we will also update our
4:22:46
answer to be of length four so far. Now again we will add a right value over
4:22:52
here. So when we add the right pointer over here and at this moment this is a.
4:22:58
So we try to check that whether a exist in our hash set or not and we can realize that okay a exist already. So
4:23:05
immediately because a exist now we will have to move this left pointer up until the point where we encounter this a. So
4:23:12
okay this b we can ignore this and we'll jump our left pointer. Okay, left pointer comes over here and again this
4:23:18
is a. So again we will ignore this and then we will come for the left pointer to be over here which means that left
4:23:24
pointer is going to be here and right pointer is going to be here and also at the same time we will have to remove the
4:23:29
this B and A from our hash set that we were currently visiting. So currently
4:23:34
the entries we have is T and M only. And then because this right is at this position number A. So we are going to
4:23:40
add an entry for A. And now we are going to uh update the and so far the length
4:23:46
of this one is actually three. So we don't need to update in our answer. And then again we are going to update the
4:23:52
right pointer. So right pointer comes over here. This is n does not exist inside the hash uh hash set. So we will
4:23:58
add an entry called n over here. And then this length is actually four. So answer is four. So we don't need to
4:24:04
update so far. And then if we do try to do next to uh this right pointer we come to the end of the list. and uh the
4:24:12
string is empty now. So because we are done iterating over the entire string now all we need to do is return whatever
4:24:18
the answer we found in this case and the answer we found in this case is four and that would be our final solution. So if
4:24:25
we see the time and space complexity in this one it's actually really efficient. So in terms of time complexity we are
4:24:30
actually completing all of these things in a single iteration. So it's actually big of n and in terms of space
4:24:37
complexity we are using this additional hashet to store the value and uh the
4:24:42
space complexity at any given moment is actually going to be bigo of whatever the answer we have or whatever the
4:24:48
longest increasing subsequence we have because remember at any moment we are only having that whatever the maximum
4:24:55
number of uh unique characters in the substring we have. uh the moment we increase the the moment we encounter
4:25:02
repeating character we are actually getting rid of all of them. So that's why the space complexity is going to be
4:25:07
bigo of whatever the longest repeating character we have we have found so far.
4:25:16
First of all we are going to check couple of edge cases that if the given string is empty or if it only has one
4:25:22
character then we will return. So now we are going to initialize couple of variables called left and right and
4:25:28
we are going to initialize its value to zero. We're also going to initialize a variable called answer and by default we
4:25:34
are going to have the value as zero and we are going to initialize a hash set of characters.
4:25:40
So first of all we are going to run a while loop uh till the point where right reaches to the end of the string. First
4:25:48
of all, we are going to initialize a character variable and uh to find the value of that particular uh index
4:25:56
and then we will check that whether this uh value exist inside our hash set or not.
4:26:02
So if the value exists inside our hash set, we are going to remove it from our hash set and we are also going to update
4:26:09
the value of our left pointer. And if the value does not exist, we are
4:26:14
going to add it to our hash set. And then we are going to calculate that whether the current answer we have is
4:26:21
actually greater than whatever the answer we had before. And we are going to do right minus left
4:26:28
+ one. And uh at the end we are going to update
4:26:35
the right pointer as well. And that should be it. So when this both
4:26:41
of these loop runs and after it ends we should have our answer inside the answer variable. So we can simply return that.
4:26:48
Now let's try to run this code. Okay. Seems like our solution is working
4:26:54
as expected. Let's try to submit it. And our code runs as expected. I will be
4:27:00
posting this solution inside the comments.
4:27:10
Hello friends, hope you're having a fantastic day today. So in this video we are going to do an awesome lead code problem called sliding window maximum.
4:27:17
This problem has been asked at tons of different companies. It is extremely welllike and also a lead code hard
4:27:22
problem. So without any delay, let's get started. Now let's try to understand the problem statement for this problem. We
4:27:29
are basically given an array of integer called nums. And we are also told that there is a sliding window of size k
4:27:37
which is moving from the very left of the array to the very right of the array. So which means sliding window is
4:27:43
moving constantly. Now we are told that we can only see the k numbers of the sliding window and each time the sliding
4:27:50
window moves one step to the right position. Now we need to return the maximum sliding window for every single
4:27:56
sliding window that we have been able to find. So let's try to see some example for this given problem. So initially the
4:28:03
window is going to be located at this position. Then window is going to keep on moving one step towards the right.
4:28:10
Which means this one is going to get eliminated and we would have a new window created like this. Same way this
4:28:16
three is going to get eliminated and we would have a new window created like this. For every single moment we need to
4:28:22
return the maximum sliding window. Okay. is that for this we will have to create
4:28:27
another array where we are going to note that what was the maximum character for every single sliding window that we have
4:28:34
we have been able to make. So the very first sliding window is going to be this portion 1 3 and minus one which means
4:28:40
the maximum value in this one is value number three. So we are going to add value number three to our answer. Next
4:28:46
this one gets eliminated from the given uh input array and then we will have a
4:28:51
new window that appears of this size which means once again the maximum value is going to be three. So we are going to
4:28:57
mark three as the maximum value. Next for this window now we have this value number five that is going to be the
4:29:04
maximum window for the current given input. So now we are going to add five to our answer. Same way we will also
4:29:10
have five for this particular window as well. and we will add five once again.
4:29:16
Now we also get rid of this element and now we have this window to look after. So in this case we have a new maximum
4:29:23
value that is six. And then in the end we will have this last window where it contains seven as the maximum value. And
4:29:30
this is the answer that we will have to return in order to understand that what is going to be the maximum sliding
4:29:36
window. So this is what is expected of us to return
4:29:43
for the brute force approach. The way we are going to do is that we are first of all going to create a window of size K.
4:29:50
So suppose even in this case we are given K is equal to three. We create this window. Then we iterate over every
4:29:57
single element and we try to find the maximum element. So we found maximum element as three. So we mark that as the
4:30:03
answer. Then we get rid of this one. we create another window and once again repeat the same process until we reach
4:30:10
to the very end and then we would be able to find the solution. Now in this case the answer works perfectly fine but
4:30:17
the issue is for every single element we will have to iterate over three different elements to find the answer
4:30:23
and every single time we are creating a new window which means the time complexity is going to be big of n cross
4:30:29
k which is an expensive time complexity. So let's see that how can we improve on
4:30:36
this one. Uh one major improvement that we can
4:30:42
make for this our given input is that instead of every single time creating a
4:30:48
new window, what if we just use this logic of this existing window we already
4:30:53
had and try to find the maximum value that we have already identified and then move forward and then play around with
4:31:00
that maximum value. that is one of the option and this is going to be an
4:31:06
intermediary step that we are going to use in order to generate the optimal solution. So that's why I'm explaining
4:31:13
this approach. The idea I'm suggesting is that let's say in this case first of
4:31:18
all we have a an element called max. This max element is going to keep track
4:31:23
of the maximum character that we currently have inside our array as the window. Okay. And uh let's say that
4:31:31
first okay currently we are at value number one which means we can only start
4:31:36
adding the value after we have reached to the index value two. So any value
4:31:43
before that should not be added to the answer or should not be treated inside our answer array. But we can still keep
4:31:49
keep track of the maximum element we have been able to find so far. So the idea is that first the value number is
4:31:56
zero. Okay. Currently maximum value is null. So we can add the maximum value we
4:32:02
have been able to find so far as this value one. Then we are at value number one. Now once again this value is two.
4:32:09
So because 2 is greater than one. So we will add value number two as the maximum element we have been able to find so
4:32:15
far. Then we are at this third value that is minus 3 uh sorry minus 5. So once again the maximum element we have
4:32:22
been able to find is two. So we are amongst for this first window we will
4:32:27
have to add one answer and that answer we can directly take from our maximum element. So we can take value number
4:32:32
two. Next we will have to add one more element. So now we are at this value
4:32:38
number six. After at value number six this six is definitely greater than the
4:32:43
current maximum value we had. So we can add value number six as the answer for this one. Okay. And now once again we
4:32:50
will have to add the maximum value. So we can add value number six over here. Once again we find value number seven.
4:32:56
So that is going to replace our maximum value. And then value number eight that is also going to replace our maximum
4:33:01
value. So we can add value these values like this and build an answer. So you must be thinking that hey this looks
4:33:08
quite straightforward then why is it even this a hard problem. The thing is we actually intentionally I chose an
4:33:15
input like this because this is a very simple input where we don't have any particular uh issues. But if we are
4:33:22
given an input let's say now in this case currently we are going to put our
4:33:28
maximum value as this value number three. Okay. And then now we are iterating over for this first sliding
4:33:35
window. We will have to choose value number three. But the thing is we are not sure which value number three we
4:33:40
picked. And in this case, let's assume that this becomes a value number.
4:33:46
Instead of this being four, this is one. Okay. So let's assume that in this case, so far we know that this is the three
4:33:53
that we added. But it could also be this three. And now when we do move to the
4:33:58
next element, which three do we have to remove? Because we are not keeping track of the index value of the maximum
4:34:05
element. And that's why when our sliding window moves, we would be confused with this element. So that is problem number
4:34:11
one. Uh the second problem that we can think of is that we are not dropping the
4:34:16
elements as we are moving forward. So every single time we move forward, we will have to drop all the elements that
4:34:23
have already passed the given existing window. Which means uh the approach that
4:34:29
we found is to use the maximum element is correct. But the problem is that
4:34:35
number one we are storing the value. That is an issue because we don't know that what is the index position. That
4:34:41
can be fixed by storing the index position. But second issue is that we are only too much focused on just one
4:34:47
character. Meanwhile, we should be focused on an entire window rather than just one character. And the approach of
4:34:55
this window is very simple and very straightforward that at every given moment whichever the first element that
4:35:02
enter inside the window would be the first element to be kicked out of the window when we move to the next window.
4:35:09
So using these two approaches what I'm suggesting is that instead of using a maximum variable just to store the value
4:35:17
I'm suggesting that instead of this number one instead of storing value we store index values. So index values will
4:35:24
allow us to calculate that whether we are at the current window or not which means it would help us to kick elements
4:35:30
out. And second thing is that uh in uh instead of only using one variable
4:35:36
because we are using an an input of a window where we are continuously
4:35:42
removing the previous elements which means we are uh using the concept of first in first out for the current to
4:35:49
maintain the current window which means we can have a Q where we can keep track of the values that are currently present
4:35:55
inside the given window and we know the concept of Q is very simple it's first in first out so we can manage is that on
4:36:02
top of it inside the given existing window we don't have to worry about
4:36:07
storing all the three elements we only have to worry about that what is the maximum element in any given window so
4:36:14
what we can do is that for our given que we will always keep track of the maximum
4:36:20
element that we have been able to find at the very first location so that we
4:36:26
don't have to iterate over the entire que to find the value we can simply do a peak operation to see that what has been
4:36:33
the maximum value inside the given sliding window. And now this should be able to solve lot of the issues we were
4:36:40
facing previously. So let's understand the approach I am suggesting. The logic
4:36:45
is quite simple. Let's quickly take one example. Okay. So let's say that this is
4:36:51
the given input that we are dealing with and we are given that the value k is equal to 3. Now I have created an array
4:36:57
to store our answer and I have also created a queue where we are going to store all the values of the given
4:37:04
current window inside the uh ascending order and we are going to maintain the
4:37:09
maximum value as going to be the very first element inside the cube that is going to help us out a lot. Uh once
4:37:16
again I'm iterating we are going to store the index values inside the cube not the actual values itself. So we can
4:37:23
quickly navigate that what should be the current window size. Okay. So I hope this these things makes clear and
4:37:30
remember that since our given k is equal to three we can only able to start
4:37:35
adding values after we reach to the index value two onwards. Okay. And I'm
4:37:40
also creating one more variable I just to understand that what is the current variable we are iterating over. So let's
4:37:47
say that currently I is equal to zero we are iterating over which means this value. Now currently our Q is empty
4:37:52
which means we don't have any maximum values. So let's quickly add the add one value. So currently our Q contains just
4:37:59
one element that is zero. And I'm also writing the corresponding value one just for our sake of understanding. Okay. Now
4:38:07
we cannot add anything to the answer until this point. So we are going to move forward. Now once again we
4:38:13
identified index value number one that contains value number three. So this value is actually greater than the
4:38:19
current value of the index position we have inside the cube which means that we
4:38:24
need to add this three over here. So we are going to add value number one as an
4:38:29
index value and which has the corresponding value three and we are simply going to remove this value number
4:38:36
one or this index value zero all itself. Why? Because for any given window size
4:38:42
that we are able to create, it is always going to be that this is going to be the maximum element. So why do we even keep
4:38:48
the non-mim elements inside the cube? So the moment we are going to identify any maximum element, we are going to iterate
4:38:55
over the given existing cube to remove all the elements that are going to be smaller than that for that particular
4:39:01
sliding window. That is going to help us out a ton. Okay. So now we got rid of this element. Okay. Now still we cannot
4:39:09
add anything to the answer. So now we are at i is equal to 2 position. So currently this is value number minus1.
4:39:16
So minus1 is actually not greater or smaller than the current maximum value we have inside the que. Which means we
4:39:23
are still going to add it inside the cube as index value number two which contains value minus one. But we this
4:39:30
would not be the first position. And now since at this I is equal to 2 position is equal to K is equal to 3 which means
4:39:37
we are at our first window. Now whatever the maximum element we have inside our
4:39:42
cube at the very first position we are simply going to peak that index value and then go back to our actual uh given
4:39:50
input array and find that maximum element and put it in the answer array. So now we are going to put value number
4:39:55
three first. Okay. Now we are at index position number three. So once again
4:40:00
index position number three the value is minus3. Now what is the current maximum value we has we have inside our cube
4:40:07
that is index number one which means in our for our i position what is the
4:40:13
sliding window it is value 1 2 and three which means the very first element inside the q we have is still inside the
4:40:20
valid window. So we don't have to kick that that value out. That is number one thing we need to check. Next we need to
4:40:26
check the value for index i is equal to 3. So this value is minus3. So because this value is minus3, it is less than
4:40:33
the current maximum value we have. We are going to add it normally inside our cube. So we are going to add index
4:40:40
position number three which is which corresponds with the value number minus 3. Okay. Now and once again we will have
4:40:47
to add the maximum value because now for every single value we are going to add one value inside the answer and once
4:40:53
again for maximum value we are simply going to do a peak on very first element. that is our maximum value and
4:40:59
we are simply going to add it inside our cube. Okay. Now next we are at I is
4:41:04
equal to position number four. So now we are at I is equal to position number
4:41:09
four. For this one the window size is going to be 2 3 and four not one. So one
4:41:15
should be removed. And currently in the very first element of the Q we have value number one. So which means we are
4:41:21
going to remove value number one right here and now. Okay. Now after this we are going to compare the value that we
4:41:28
currently have for this value number four that is this value number five and we are going to compare it with very
4:41:34
first element. So since five is greater which means the moment we identify that the five is greater we are going to
4:41:40
check every single element that are smaller than five and we are going to remove all of them. We don't need them
4:41:46
inside the window because we are only keeping track of the maximum elements. So now we are going to store index
4:41:52
number four that contains value number five and after doing this we are going to once again add it to the answer. So
4:41:58
we are going to add value number five to the answer. Next is element number five that contains value number three. So
4:42:04
once again this particular value inside our Q index number four is still part of
4:42:10
the current sliding window. So now we are going to check the values. So three is obviously less than value number
4:42:17
five. So we are going to add value number index number five or value number three inside our given Q. Uh and then
4:42:24
once again we are going to add value to the answer that is once again going to be value number five. Now we are at this
4:42:31
position where the value is value number six. And once again I just uh for our
4:42:36
understanding we are dealing with this window. So index values 4 5 and 6. Okay.
4:42:42
Now for this I is equal to 6 we will first check that whether four needs to
4:42:48
be removed. No it it can stay there for now. Now we compare the value. So currently this value number six or the
4:42:54
index i is equal to 6 contains the value number six that is greater than the index position four that contains value
4:43:00
number five. So we are going to get rid of this one and we are going to check all the values that are smaller than six. So currently all of these values
4:43:07
were smaller than six and we are only going to store index number six. Answer number six. Once again marking six as
4:43:13
the answer. And lastly we are at I is equal to 7. So if I is equal to 7 then
4:43:18
the valid Q or the valid window becomes 5, 6 and 7 index values. So the current
4:43:25
index value we have inside the Q is 6 which is still valid. Then we compare the values. So 7 is greater than six
4:43:32
which means we are going to replace six with value number seven and which also coincidentally have the value number
4:43:38
seven. And then uh because this is the maximum value we are able to find, we are going to also mark it to the answer.
4:43:45
And in the end, we are just simply going to be done with our existing loop. And that's it. This is the whole approach.
4:43:51
And this is the whole solution that gives us the desired answer in a single iteration on the given input array. And
4:43:59
all we are doing is just sometimes we are doing repeated work inside the que to change the value of the array. But
4:44:07
apart from that we are not doing anything. So this is a wonderful approach to solve this problem. And this is actually the optimal solution. If we
4:44:13
see time and space complexity for this approach the time complexity is actually going to be big of n because we are
4:44:20
simply going to be iterating over this given input array once which is pretty awesome and pretty convenient. Um so
4:44:26
yeah that's that's it. And in terms of space complexity because we are using an extra Q so that is going to be big of K
4:44:33
because at max this can be of size Q nothing more than that. So let's try to run this code and u so now let's try to
4:44:41
so now let's try to build the coding solution for this one.
4:44:47
Okay. So this is the coding solution. First we are checking for some some edge cases that if the given input is equal
4:44:53
to null or if the given k is equal to less than zero then we can just simply return a blank and or an empty array. If
4:45:00
that is not the case first we add we initiate an variable to store the the length of the array. Then we also create
4:45:06
a new value to store the result of the given array and then we are also
4:45:12
initializing a dq to store the q values that we just discussed in the solution.
4:45:18
Now we are simply creating an array to iterate over the given list. Very first we are checking that are there any
4:45:24
indices inside the current window that are exceeding or that needs to be kicked out. For that first we check that if the
4:45:31
given q is not empty and the very first element or the largest element inside
4:45:36
our given q. If that is less than the value of i minus k + 1 if that is the
4:45:43
case then we simply pull that element out. If that is not the case, then we
4:45:48
simply iterate over all the values that are smaller than the given current value. If we identify that scenario, we
4:45:55
simply keep on iterating all the values and keep on removing them. Then we simply have to add the value to the cube
4:46:01
and we need to find the maximum value that is currently located at the very first location inside the cube to our
4:46:07
array and we simply add it after the value I is I becomes greater than the
4:46:14
value of K minus one that we just explained and in the end our result array should have been populated. So we
4:46:20
can simply add all the values and return that. So let's try to run this code.
4:46:30
Okay, seems like our solution is working as expected. Let's submit this code
4:46:36
and our code runs extremely fast compared to lot of other solutions. Uh once again the coding solution is
4:46:42
present on the GitHub repository that we have created. So you can go and check it out from there. Thank you.
4:46:54
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do minimum window substring
4:47:01
problem. And if we see some of the companies where I want to get a job, there are companies like Facebook, Amazon, LinkedIn, Microsoft, Lyft,
4:47:08
Airbnb, Apple, Adobe, Google, Snapchat, Flipkart, Bite Dance, Spotify, Tik Tok,
4:47:14
Bloomberg, Uber, Pinterest and Goldman Sachs who have already asked this question. So that's why I'm paying my
4:47:19
utmost attention. I hope you also enjoy the video. So this is a lead code hard problem but
4:47:26
it is also a very well-liked hard problem. Basically we are given two strings called s and t and we are given
4:47:32
the length m and n respectively for each s and t strings. Now we need to return the minimum window substring of given
4:47:40
string such that every character in T including all the duplicates that is the
4:47:45
key part is included in the window that we have created from this s and if there
4:47:50
is no such window then we need to return the empty string. So if we try to understand this with an example if we
4:47:56
take take this example for instance we are given a string s that looks like this and we are given a t that looks
4:48:02
like this. Now we need to return a substring in this given such that this ABC is present. Now we don't care about
4:48:09
the order of this ABC. They can be in any order in the new substring that we are trying to create. But we need to
4:48:15
return the smallest substring. So if we see one of the substrings that where this ABC is present, we can find a
4:48:21
substring that looks like this. If we see this particular substring for an instance, we can see character A, B and
4:48:28
C is being pro presented. But the thing is if the question is is this the minimum window substring? No, this is
4:48:33
not the minimum window substring. Why? Because there exist actually a smaller substring where ABC, BC is also present.
4:48:39
And we can take one more substring that looks like this. So this substring is smaller than this first one where also
4:48:46
A, B and C is also present though they are in different order. But this is again not the minimum substring. uh
4:48:54
there is actually a substring which is B A and C where all the values of A B C is
4:49:00
present that is continuous substring of this S and this is the minimum substring where we can find all the characters
4:49:06
that are present in T and we need to return this as an answer. If we see couple of more examples over here
4:49:12
suppose we are given S is equal to A and T al also equal to A. We can simply return A as the substring because that
4:49:19
is the only substring we can create. Now if we are given s is equal to a and t is equal to double a which means that there
4:49:25
is no way possible for us to create double a from this single a. So in this case we need to return an empty string.
4:49:30
So now since we have understood the problem let's see that what would be the different approaches to solve this problem. So first of all I'll show you
4:49:36
the brute force approach and if you directly want to check that what is the optimal solution I have already provided
4:49:42
the timestamp so you can directly jump onto the optimal solution as well. Okay, suppose this is the S and this is
4:49:48
the T we are given. We are looking for a substring inside this given S which
4:49:53
contains all the letters of this T and we need to find the minimum length substring for that. Now we can clearly
4:50:00
see that there is one substring HBO which contains all of the elements of that are present in T. But the smallest
4:50:06
substring we need is actually OB which contains all the elements of this T and that contains the smallest length. The
4:50:13
brute force way to solve this problem is that we actually start creating every single possible substring out out of
4:50:19
this given string s. So we can create substrings like we will check that okay
4:50:24
this can be a potential answer. We will put it as a potential answer and we will mark its length. Now uh eventually we
4:50:32
would find a substring that looks like this OBH and that is the correct answer and then we would return this answer as
4:50:38
our solution. So this solution will also guarantee to provide us the right answer. But this right answer is
4:50:44
actually very costly. Why very costly? Because we know that it takes big of n² to actually create all the substrings.
4:50:50
And for every single substring we will have to check that whether it contains all the elements of t or not. Which means we will have to multiply this by
4:50:57
the whatever the length of t is which is uh let's say m in this case which means that we we are actually essentially
4:51:03
doing we go of n cq work to solve this problem which is very expensive.
4:51:09
Okay, suppose this is the example that we are given and we are trying to find that what is the minimum substring
4:51:14
inside this given S where all the characters of this T is pres present. So to optimally solve this problem we are
4:51:20
actually going to use sliding window technique with two pointers. So now I have presented the input in a
4:51:27
slightly different format and I have also created uh that what is the answer we are going to store because remember in the answer we need to return that
4:51:34
what is the minimum substring and for any minimum substring we need the left pointer and right pointer value and we
4:51:39
also need the length and we will only choose the minimum length. Now initially we are going to have our left and right
4:51:44
both pointers starting at the first position and now what we will have to check is that we are going to have our
4:51:49
right pointer go on the right side until the point where we create a substring where all of these a b and c are
4:51:56
present. The moment we do that we will note down that what is the answer we have found so far. What is the minimum
4:52:01
length? What is the left pointer? What is the right pointer? Once we do that, we will start updating the value of the left pointer to go on the right side
4:52:08
until the point when this condition is no longer true and we are not able to make ABC in the given left and right
4:52:14
string and again we will update the process on our right portion and then again we will try to see that whether we
4:52:19
can find a better substring or not. So let's see this approach in action. So now to achieve this uh approach what we
4:52:26
are going to need is that we have we already have our two pointers left and right over here. Now we need to check
4:52:31
that at any given substring whether this T is present or not. So if we for every
4:52:36
single substring try to check that whether the all of the characters of T is present or not it takes lot of time.
4:52:42
One quick way to do it is that we actually create a hashmap for all the characters that are present inside this
4:52:47
value number T and inside the hashmap we note that what is the uh elements and what are the number of occurrences they
4:52:53
have. So in this case for this P hashmap we actually have three characters only
4:52:59
and we have one occurrence of each of them. So we are going to note it somewhere. So it becomes easier for us
4:53:04
to record. Now at the same time for any substring that we create we will also have to check that whether we have all
4:53:10
the satisfied words inside our substring or not. So again we are going to create a hash hashmap for our substring that we
4:53:17
are creating as well. And inside the substring hashmap we are going to keep on adding the values as we move forward.
4:53:24
Now uh to check hashmap every single time is not a very good approach. A better approach in this case could be
4:53:31
that we already know that what are the number of unique characters we need inside this hashmap. So why don't we
4:53:36
just create two variables called the number of unique characters. So we just name it as unique uh that are present
4:53:43
inside this t hashmap from this given original input and whatever the substring inside the substring whatever
4:53:49
the unique characters that we have already been able to create. So let's just say that uh this name is create and
4:53:58
we will keep track of it right I'll just uh show you that how we are doing everything when we keep moving forward
4:54:03
on the uh with our example. So initially left and r both both are at this
4:54:08
position and currently we will note that okay a is not present inside our given substring. So we will add an entry for a
4:54:15
and so far we have received one occurrence so far. Right now uh originally this t hashmap had three
4:54:20
unique characters. So we are going to note that that there are three unique characters that we have to find in any given substring. And so far because this
4:54:28
current right position is at a we have already found one of the characters of the required occurrence. Right? So we
4:54:34
will note down that okay we have already received one of the characters. Now our right pointer is going to the next element because we haven't satisfied our
4:54:41
full condition. So now we identify that okay this value is actually B. So we are going to add an entry over here inside
4:54:47
our substring hashmap and we are going to say that we have found one occurrence of B and this one occurrence of B is
4:54:52
already also required inside this given hashmap as well. So we can note down that okay out of this three required we
4:54:59
have actually found two unique characters that are needed right we are good so far. Now uh next thing we are
4:55:05
going to do is that again again over here we we are going to update the value for right pointer. We encounter that
4:55:10
this value is actually a. So we are going to add one more entry to our
4:55:15
required pointer. So over here we have found two occurrences of a but that does not solve our problem because our unique
4:55:21
and create are still not same. So now we are going to update the value of our R again. So now again R is at this
4:55:28
position X. X is not present over here. So we will add an entry for X is equal to 1. But this X is actually not present
4:55:33
in this T hashmap. So we can't do anything about it. Uh now again we were going to update our value of R. So R is
4:55:41
at this position. Now because R is at this position remember that this is the value of C. C is actually one. C was the
4:55:47
remaining value inside this T hashmap. Now we have three unique characters that were needed and we have already created
4:55:53
three unique characters inside this given hash. So now we are going to treat this substring as our answer because
4:55:59
remember we needed to have the values a b c and a b c are actually present over
4:56:05
here. This is a this is b and this is c inside this given left to right substring. So we have found one
4:56:10
potential answer. So first of all we are going to check that okay what is the length of this one. So length in this case is 0 1 2 3 4. So length is actually
4:56:17
five and the left pointer is at zero position and right pointer is at four position and we are able to add this
4:56:23
entry to our answer because we don't have anything before. So that's why we were able to add an entry to our answer.
4:56:28
Now we are going to update our left pointer until to the point when this condition is no longer true. So now
4:56:33
because previous value of left pointer was over here and now we jump to jump to this place. So now left pointer is at
4:56:39
here. But the moment we updated the left pointer, we will also have to remove the value of our uh reduce the value inside
4:56:47
our substring hash set hashmap. So now a there is only one occurrence of a. So
4:56:53
far this condition is already true because both this three and three is matching. Right? Now again we are going
4:56:59
to update the value of our left pointer to one more character. So now left pointer is over here. Now this B is
4:57:04
actually zero. So we are going to remove the entry for B. Now because we removed the entry for B, we have only created
4:57:10
two elements that are needed inside this substring from this position two to position four which is A and C. We don't
4:57:17
have B entry which means now we will have to update the value for right pointer until we find the B. Now lucky
4:57:22
for us B is actually very next to this right pointer. So now right pointer is over here and B is actually over here.
4:57:29
So B is one. We will add an entry over here. And now we have already created all of three elements needed uh rather
4:57:35
than two and we are done with this case right. So which means we can say that this uh new substring is also a
4:57:42
potential answer. And let's see that whether this substring is actually better than our previous answer or no.
4:57:48
How can we determine that? Remember uh the aim of this question is to find the minimum length of the substring. So we
4:57:54
are going to compare the length of this one. So length of this one is actually four and the current answer we had was
4:57:59
actually of length five which means it it is in our interest to update the length over here and the moment we update the length we will also have to
4:58:05
update the left and right pointer over here. So left pointer currently is at two position and right pointer is at
4:58:11
currently at five position. Now we have found a potentially better answer. Now again we are going to update our left
4:58:16
value because we have already find the answer. So now left comes over here which means we will have to reduce this value of a. So again we are going to
4:58:22
reduce the value of a. So a is now zero. So there are no occurrences of a because there are no occurrences of a uh in this
4:58:29
new substring we we have only created two elements out of this three unique characters that we are needed and which
4:58:35
we can see in this particular uh substring substring from this position number three to position number five
4:58:40
that we only have c and b we don't have a now we are going to update the value of our right pointer now again when we
4:58:46
update the value of a right pointer lucky for us we are actually able to find one a so we will add an entry
4:58:51
inside our substring hash set that okay now we have found one character Now we can say that we have created all three
4:58:56
characters that were needed. Now this is also potentially a new substring and can this be a better answer? So we'll check.
4:59:02
Okay, in our length we already have an answer of four uh inside our uh answer
4:59:08
array that we have stored and this is also an size of four. So which means that there is no point in updating our
4:59:14
answer. We have we already have the same answer with the same length. So we are we are going just going to go to the
4:59:20
next case. So now again we increase our value of left. So now left is again at this position. So we will have to ignore
4:59:26
this X because we already got rid of it. Which means that we have already traveled all the values so far. And now
4:59:33
we are at CBA. Now CBA again this is all of these three elements that were needed
4:59:40
and we already have that which means that this is also potentially a better uh a better substring that we have found
4:59:48
and the length of this is actually three. So because the length of this is three this can be a better answer. So we
4:59:53
will note it down. So this is three. Now left pointer value is four and right pointer value is six. So we have found a
4:59:59
potentially better answer. Since we have already found an answer and we know that this is a valid substring. Now we'll have to update the value of our left
5:00:04
pointer. So once we update the value of our left pointer, we are actually going to ignore the C. So now we get rid of
5:00:10
the C inside our hash set. Now we are we also get rid of this L. And now we have taken care of all of these elements so
5:00:17
far. Now that we only have BA which means we only have two elements uh out of three that we we needed. Now again we
5:00:23
will have to update the value of our right pointer. So again we update the value of our right pointer over here. Uh we find that okay this value is actually
5:00:30
C. C occurrence is one. We which means we have created this element actually three. Uh all of this is successful. Now
5:00:37
the we check that okay length of this is actually three. We already have an answer of length three which means there is no point in updating that. Now we
5:00:44
will update the value for left pointer. we will ignore this B. So if we ignore this B, now we only have two elements
5:00:50
out of three needed. So because we have two needed, we will have to update the right pointer. So now when we update the
5:00:55
right pointer, we are actually going to be at the end of our uh string. And because we are at the end of our string,
5:01:02
we can actually break out of the loop. And the moment we break out of the loop, which means that whatever the value we
5:01:07
have stored inside the answer, we have the left pointer, we have the right pointer. So all we need to do is we need to return the substring. So if we return
5:01:13
the substring in this case, we will have to return the substring that looks like this. So the answer in this case is
5:01:19
actually going to be CBA which is the minimum substring that we can achieve that contains all the elements of the T
5:01:26
that are present over here. And remember over here we are using hashmap and substring hashmap to find the answer. In
5:01:33
order to make our lives easier, we have created two elements to know that what are the unique characters that we need
5:01:38
to compare. In case because this was a string and we know that there can be only a finite number of unique
5:01:44
characters which is 26. We were able to use this technique. But your interviewer is for sure going to ask you that rather
5:01:50
than having a string and having finite number of unique characters, you are actually going to have millions of hash
5:01:56
code characters or something like that. In that case you will not use this technique and you will actually just
5:02:01
simply have to check over the hashmap for every single substring that you are going to make. So this is one of the
5:02:08
approach where we can find the optimal solution and uh it works as expected. If we see the time complexity the time
5:02:14
complexity is actually go of whatever the length of string is plus whatever the length of t is. And why we are able
5:02:20
to achieve this uh time and space complexity because we are using this technique. So that makes our lives a
5:02:25
little bit easier. If we see the space complexity, the space complexity is also going to be actually bigger of the
5:02:31
whatever the size of S is plus whatever the size of P is. And this also works uh
5:02:37
because we are creating two additional hashmaps and we need to take care of that space into account. But overall
5:02:43
this is still much bigger improvement in compared to our brute force approach. Now there is one more approach to solve
5:02:48
this problem. Uh that whatever the input that is already
5:02:56
given. First of all whatever we we create the same hashmap we create for this element number T. Which means that
5:03:02
we actually use the same hashmap that I have drawn over here to compare all the values of T. But uh for this value
5:03:10
number s actually remember that we only need to find the substring of characters
5:03:15
that are present in t. But so if that is the requirement why do we even bother
5:03:20
checking this element x or any other element that is not one of these values.
5:03:26
So a better way to solve this problem is to create another hashmap where we ignore this X and we only keep character
5:03:34
inside this given string that are also present in the inside this given T and in this particular hashmap we also
5:03:41
identify that what is the index value for every single element. So in this case we will determine that okay this A
5:03:47
is actually present at zero position. Then again we have a B that is present at first position. uh again we will
5:03:53
mention that there is an A that is pres present at third uh sorry second position and so on and so forth and then
5:04:00
it will make our lives a little bit easier and we can solve this problem but I don't think in the in an interview
5:04:06
even if you show this approach they are going to completely reject your suggestion so that is why I am choosing
5:04:12
this one let me know in the comments if you want me to solve the other approach as well where we are only going to use
5:04:18
the unique characters that are also present inside this given
5:04:25
So first of all we are going to check some edge cases if the given string is empty or if the length of the given t is
5:04:31
actually greater than length of s. If that is the case we can simply return uh as empty string.
5:04:38
Now if that is not the case we will create a hashmap to store the value of this t string inside the hashmap for all
5:04:45
of its characters. We are going to name it as map t. Now we
5:04:50
are going to run a for loop across this given string T and we are going to add all the entries to our map T.
5:05:00
After the loop ends, we are going to create a variable called required that gives us the number of unique characters
5:05:06
that are present inside our given map T hashmap. Now we are going to initialize bunch of
5:05:12
different variables to keep track of different things. So first of all we are going to initialize variable called left
5:05:17
and right to keep track of our two pointers. Once that is done we will create a variable called create uh that
5:05:24
defines that what are the number of variables that we have created so far uh that are also present inside the given t
5:05:31
and we are going to initialize an uh integer array uh to store the value of
5:05:36
answer. And we are going to initialize the first value as minus1 inside the answer where we are going to keep track
5:05:42
of the length of current substring. And we are going to have two more entries to store the value of left and right
5:05:48
pointer. And we are going to initialize those values as zero as well. Uh we will also create a hashmap to keep track of
5:05:54
all the values that we have found so far inside the current uh substring.
5:06:00
And now we are going to run our while loop across the string s. And we are going to run it until the right pointer
5:06:06
reaches to the end of the string. So inside our uh loop first of all we are
5:06:11
going to add an entry to our hashmap for any particular given substring
5:06:17
after adding a value to our substring. Now we will check that whether all the elements we have added in the substring
5:06:23
is that element also present inside our map t as well. If that is the case we
5:06:28
can increment the value of number of characters that we have created in our substring that are also required inside
5:06:35
our map t as well. If this condition is true, we will update the value of our create variable.
5:06:45
Now after updating that, we will also have to check that whether the current substring if that is valid or not. And
5:06:50
by valid, I mean that whether the required and create has the same value. If that is the case, we will have to update the left pointer and we will have
5:06:57
to shrink our uh size. Also, we will have to add entries to our answer
5:07:03
array as well. So we are going to run another while loop that while left is less than or equal to right
5:07:12
and the required is and created are same.
5:07:18
We are going to check that whether we need to update our answer or not. And we are also going to update the value of
5:07:24
the character uh C variable to help us in doing lot of other things. And we are
5:07:30
going to assign it the value of the current left pointer. Now we check if we need to update the
5:07:36
answer. After updating the answer value, we will
5:07:43
also have to remove the entry from our substring map because we are updating the left pointer.
5:07:50
And after removing the entry again we will have to check that whether the value of our uh entry that we just
5:07:56
removed did it caused us to reduce our create variable which means that have we
5:08:01
removed any entry which was also present inside our map t hashmap as well which
5:08:07
was required for us. If that is the case we will have to reduce the value of our create variable and it could it could
5:08:13
make us break out of this loop as well. In any case, we will have to update the left pointer. So, we'll update the value
5:08:19
of left pointer. And after that is done, we are done with the inner loop. Uh in the outer loop, we will have to update
5:08:26
the value of right pointer. And that's it. So basically after this loop ends,
5:08:31
essentially we would have taken care of all the scenarios uh that are needed for this loop. And now we will work on
5:08:38
returning the answer. So for the answer we will have to check that if the value of answer of zero is
5:08:46
equal to minus1 which means that we are not able to find any value that were suitable to create as a valid substring.
5:08:52
If that is the case we will return an empty string. If that is not the case we will return the value inside our answer
5:08:59
array for this left and right pointer value which means answer of one and answer of two. But we will have to do right + one. Why + one? Because the
5:09:07
indexing works from 0 to r. So that's why we'll have to add one more entry to our right.
5:09:14
Let me try to run this code. Oh, we made some mistake in generating
5:09:22
the answer.
5:09:30
Okay, seems like our code is working. Let's try to submit this code. And our code runs as expected. And uh I
5:09:37
would be posting the solution in the comments so you can check it out from there. Thank you.
5:09:54
Now let's try to understand that what is two pointers pattern. It is very closely associated with array and it's slightly
5:10:01
different from sliding window. So let's try to understand that what we are talking about. So basically in the
5:10:07
sliding window technique we typically have a kind of window associated that we
5:10:12
move for forward most likely in the left to right fashion and we keep on adding an element and removing another element.
5:10:19
Now in the two-pointer technique typically we are going to have two pointers where one begins at the start
5:10:25
position another begins at the end position. This is just an example but this is the most likely scenario and
5:10:31
they both are going to slowly come towards each other eliminating these numbers in some fashion depending on
5:10:38
certain condition. This is the whole concept of two pointer problems. Now there can be other examples where we are
5:10:45
also going to use two pointers uh in the future that is with the link list. So it's a pretty common scenario where in
5:10:52
the beginning of the link list we start uh with two pointer where one is going to be a fast pointer and other is going
5:10:57
to be small slow pointer and then we can see some interesting results but I'm not
5:11:02
spoiling anything at the moment. So let's dive deeper into interview questions that would give us the best
5:11:08
idea about what this technique and topic is. You might have seen some examples
5:11:14
but let's just dive deeper into the interview questions. Hello friends, we are not employed by a fine company. So
5:11:20
let's not stop lead coding till we get there. Today we are going to do valid palendrome lead code problem. And if we
5:11:25
see some of the companies where I want to work at who has already asked this question, there are companies like Facebook, Amazon, Microsoft, Apple,
5:11:31
Bloomberg, Spotify, Adobe, Tik Tok, Google and Uber. So that's why I am
5:11:37
paying my utmost attention. I hope you also enjoy the video. So this is a lead code easy problem and
5:11:44
basically we are given the definition of what a palendrome is. uh we are told that after converting all the uppercase
5:11:50
letters into lowerase letters and removing all the non-alpha numeric characters if the string reads same as
5:11:56
forward and backward then we can determine that any given string is a palendrome. Now we are given a string s
5:12:02
and we need to return true if the given string is palendrome if not we need to return false. So let's try to understand
5:12:08
this with an example. Over here we are given a string that looks like this where you can see that there are some
5:12:13
alpha numeric characters as well which we will have to get rid of. This is only put there just to add some sort of
5:12:20
additional complexity. Apart from that it serves no purpose.
5:12:25
This is the original string that we are given. Now if we convert all the uppercase letters to lowerase and remove
5:12:31
all the alpha numeric characters, we will actually get a string that looks like this.
5:12:36
And if we see for this particular string uh if we start going from the front and even going from the back we will see
5:12:42
that all the characters that are present from the front they are also present from the back in the same order. So that
5:12:47
is why we can determine that this string is actually a palendrome and we will return true in this case. Uh we are
5:12:52
given another example that looks like this. Over here we can also see that there are some alpha numeric characters
5:12:59
which are the two spaced values. So we will have a string that looks like this. And over here if we try to see that
5:13:05
whether this is a palendrome or not. Currently this R r matches a A matches C
5:13:10
c matches but this E actually does not match over here and over here actually
5:13:16
we have an A. So that's why this is not a palendrome and we will return false in this case. So let's see that what would
5:13:23
be the approach to solve this problem. Now suppose this is the example that we are given and we need to determine that
5:13:29
whether this given string is a palendrome or not. The approach I'm suggesting is first of all we iterate over this given string. We get rid of
5:13:35
all of these characters that are alpha nu alpha numeric. Once we do that then
5:13:41
we will create a new string that is actually reverse of this original given string. And now we have two strings in
5:13:47
at our disposal. All we have to do is compare both the strings. If they are same we can determine that they are
5:13:52
actually palendrome and we can return true. If they are not the same we can return false immediately. So let's see
5:13:58
that in the action. So first of all we are going to create a string from this original input string where we are going
5:14:03
to get rid of all of the uh non-alpha numeric characters.
5:14:08
Once we are done that now we are going to reverse the string. So we are going to create a new reverse string from this original given string and we are
5:14:15
basically reversing whatever this given input is. In this case if we compare this given uh
5:14:22
uh reverse string and whatever the string we are given they both possess the same value. Which means we can
5:14:27
determine that this given original input is actually a palendrome and we can return true in this case. So this is one
5:14:34
of the solution where we can work with and this solution would work as expected. No issues with that. Uh let's see that what would be the time and
5:14:40
space complexity over here. So the for the time complexity actually first of all we are iterating over this given
5:14:45
string to remove all of the alpha numeric characters and then again we are iterating over this given string to
5:14:51
create a new reverse string which means that we are essentially iterating over this original string two three times and
5:14:57
comparing it and uh basically we are doing big of n work but actually we are doing like big go of 2 * n work. Now in
5:15:04
terms of space complexity we are because we are creating this new original reverse string so that is why we are
5:15:09
also consuming some uh space. So that's why the space complexity in this case is also going to be big of n where n is the
5:15:15
number of characters that is present inside this given string. So this approach is okay. It's justified. It
5:15:22
works as expected. But the question is uh can we do something better in terms of space complexity and even in terms of
5:15:28
time complexity. And yes there is a better approach. And let me quickly show you how.
5:15:37
Okay. So for the optimal solution what we are going to do is suppose we are given an input that looks like this. Now
5:15:42
over here we are actually going to use a two-pointer solution and we are going to have a left pointer and a right pointer
5:15:47
and initially the left pointer is going to be located at the leftmost position and right pointer is going to be located
5:15:53
at the end of our string. Now at any given moment we are going to compare that what is the character value of left
5:15:59
and right pointer and we are also going to check that whether this given left and right pointer if that is that like a
5:16:05
non-alpha numeric value. If that is the case, we will just like uh increase the
5:16:10
value of left or right pointer. And uh if the if both the values are same, essentially we will move the left
5:16:16
pointer on the right side and we will move right pointer on the left side. And we would keep on doing this process
5:16:22
until left and right are adjacent to each other before right crosses the left. And if we are able to reach to
5:16:28
that point, we can determine that this is actually a true and valid palendrome. If that is not the case, we will
5:16:34
basically return false at any given moment. If we identify that left pointer and right pointer character values are
5:16:39
not matching up. So let's see that in action. Suppose this is the string we are given. Currently the left is located at this M and right is located at this
5:16:45
uh small M. But in both the cases we are only dealing with lowerase English letter. So even if we encounter an
5:16:51
uppercase English letter, we would convert it to lowerase English letter. We would treat treat it like this. So
5:16:56
this M is equal to M. So far we are good. Which means we will have to update the value of left and right pointer. So
5:17:01
now this left pointer is going to go to the next value which is over here. And this right pointer is going to go to a
5:17:07
previous value which is over here. Now at this position right we actually identify that this is not an alphabet.
5:17:15
So we would again update the value of right pointer and we would ignore this case and this time right pointer comes
5:17:20
over here. Now because both of these are valid alpha numeric value we will try to see that what are their values and both
5:17:27
are located a a which means they are same. So if they are same again we are good up until this point. Again we will
5:17:33
update the value of left and right pointer. So now left pointer is at D and right pointer is actually located at
5:17:38
this column over here. So because this is not an alpha numeric value again we are going to ignore this and we are
5:17:44
going to update the value for uh right pointer. So now right pointer would end up at the same position where left
5:17:51
pointer is. If we again compare the value both are going to be dd. So again we are good up until this point. Now we
5:17:57
don't have to do it but because in our algorithm we are specifying that we need to check before right pointer crosses
5:18:02
the left and in this if we do one more iteration essentially right would come and left would come over here which
5:18:09
means that they would be crossing each other and which is not what we want. So we have already concluded that all the
5:18:15
characters inside this given string they are actually part of a palendrome and we can return true in this case and this is
5:18:20
the approach we are going to take. Now if we see the time complexity in this case the time complexity is actually going to be big go of n only because we
5:18:27
are completing everything in just single iteration. We are having our left pointer move to the right side and we
5:18:33
are having our right pointer move to the left side and we stop when they meet. Now in terms of space complexity we are
5:18:40
actually uh doing it pretty efficiently. We are only using couple of pointers to store uh in our space. So that's why
5:18:47
it's only a constant space that we are consuming. And this approach is much better approach and we uh we will
5:18:52
conclude this as to be an optimal solution. Now let's move on to coding.
5:19:00
First of all we are going to initialize couple of variables called left and right and we are going to assign the left to be value zero and uh right to be
5:19:07
value uh to the end of the string. So now we are going to run a loop that
5:19:13
while left is less than right. So now first of all we are going to check that if the current value on the
5:19:19
left side if that is not alpha numeric we will have to update the value of left
5:19:24
pointer. Same thing we are going to do with the right pointer but we are actually going
5:19:31
to reduce the value for the right pointer. And if you identify that both left and
5:19:36
right are correct uh letters we are going to check check their values and if they are not same we can return false
5:19:42
immediately. If they are same, we will continue updating the loop.
5:19:48
So if that is the case, if the characters are not matching, after converting them to lower case, we can return false immediately.
5:19:55
And if that is not the case, uh we would update the values of left and right pointer.
5:20:01
And once this loop ends, essentially uh if we get out of the loop without returning false, we can simply return
5:20:07
true. Now let's try to run this code.
5:20:13
Okay, seems like our solution is working as expected. Let's submit this code. And
5:20:19
our code is actually pretty efficient. I will be posting this in the comments so you can check it out from there. Thank you.
5:20:31
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do two sum two lead code
5:20:38
problem where input array is sorted and if you see some of the companies where I want to get a job who have already asked
5:20:43
this question there are companies like Amazon, Apple, Uber, Google, Facebook, Bloomberg, Microsoft and Goldman Sachs.
5:20:49
So that's why I'm paying my utmost attention. I hope you also enjoy the video.
5:20:55
This is a lead code medium problem and also a very well-liked problem. Uh this two sum two problem is actually very
5:21:00
similar to the twosome problem which we originally solved over here. So you can check it out that solution if you want.
5:21:06
Now let's understand this problem statement. So basically we are given a one index array and this is only given
5:21:11
one index just to add some additional complexity uh nothing more than that. Uh and we are also given an array of
5:21:17
numbers. Now we are told that all the numbers they are already sorted in nondereasing or ascending order. Now we
5:21:23
need to find two such numbers that they add up to a specific target and we are also given this target value as the
5:21:29
input for our method as well. Now uh we need to provide the index values for
5:21:35
those two numbers as the answer. So let's try to understand this with couple of examples. So if we take this example
5:21:40
1 and two over here, I have drawn it much bigger over here. So first of all, we are given a nums array like this. And
5:21:46
if you notice that the indexing is actually starts from one uh rather than starting from zero. We are also given
5:21:52
some target value. So in this case, the target value is 9. So now we need to find any two values that sums up to 9.
5:21:58
So we can clearly see that 2 + 7 equals to 9. Uh and in this case we need to return the index value of this 2 and 7.
5:22:05
So the answer in this case is going to be 1 and 2 as the answer. Uh if we take second example over here we are given
5:22:11
the target value to be six. So clearly we can see that 6 is going to be the sum of actually 2 + 4. Now remember we can
5:22:17
also do over here like 3 + 3. But the thing is we cannot repeat the same character again. So in this case the
5:22:23
answer has to be 2 + 4 that equals to 6. and uh we need to return the index
5:22:28
value. So index values in in this case is going to be 1 and three and this is going to be the answer. So after
5:22:34
understanding the problem statement let's see that what are going to be the different approaches to solve this problem.
5:22:41
So the first approach that comes to our mind is a brute force approach. Now in the brute force approach what we can do
5:22:46
is we can simply take every single possible two pair that we can make and try to see that whether we can come up
5:22:53
with the target value for those two pairs. If we do get the target value, we simply return their index numbers. So in
5:22:59
this case we we are given the target to be 11. Now we can make different pairs that looks like this that first of all
5:23:05
we'll take the first number and then we will make all the possible pairs. We don't find any sum that comes up to 11.
5:23:11
So we can ignore this one. Now we will start with the second value and keep on repeating the same process. So the moment we do that when we do the sum of
5:23:18
this 5 + 6 we get 5 + 6 to be 11 and this is the answer. So in this case we can return their index value. So the
5:23:25
index values in this case is going to be 2 and three and that is that would be the answer we can return. Now this brute
5:23:31
force solution leads up to the correct answer uh in terms of the index values that we are looking for. But thing is
5:23:36
this is not the most efficient way to do it because we have to deal with lot of different uh subarrays or sub pairs. So
5:23:43
if we see time complexity for this brute force approach it actually it is actually big of n square because for
5:23:49
every single value we have to compare it with all the other remaining values and that is pretty disastrous. So let's see
5:23:55
that what is going to be the better approach. Okay. So the next approach that comes to
5:24:01
our mind is a binary search. Why binary search? Because remember we were originally told that this input array we
5:24:07
are given that is already a sorted array which means all the values that they are sorted in ascending order. So we can
5:24:14
actually use binary search to our advantage in order to find the target value pair. The approach I'm suggesting
5:24:20
is that first of all we take any value. Okay. So the current value in this case is true. Right? So if we have if two is
5:24:26
supposed to be part of this answer let's imagine that two is part of this answer. then to O2 can only be part of the
5:24:34
answer if uh the value 11 minus 2 equals to 9. If this 9 is somehow present
5:24:39
inside this given input array, we can clearly determine that 2 and 9 can be part of the answer that leads up to the
5:24:46
target value 11. So all we need to do is uh once we identify the value number two, we come up with the remaining value
5:24:52
that is needed to generate the answer that is 9. And then we can simply do a binary search in this case to see that
5:24:59
whether 9 exists or not. We can find this immediately in log and time because
5:25:05
this array is already sorted. So at any given moment all we have to do is just calculate the middle value and see on
5:25:11
which side of this middle value does this 9th falls and eventually that would lead up to the corre correct answer. So
5:25:18
first of all if we see for this value number two 9 does not exist. Right? So because 9 does not exist, we can ignore
5:25:24
the case for this value number two. And we can define that two is not part of solution that leads up to the target
5:25:30
value 11. Now again we are going to repeat the same process. Now the next value we have is five. So now if the
5:25:36
value is five, all we have to do is to see that what is going to be the remaining value and remaining value in this case is going to be 11 - 5. So 11 -
5:25:44
5 is equal to 6. So now we only have to check that whether the six exist inside the remaining array or not. And that we
5:25:51
can do using the binary search in log and time. So now what we will do is we'll try to find the middle value.
5:25:57
Let's say that middle value in this case is 12. So 12 is greater than 6. So because 12 is greater than six, we only
5:26:02
have to compare between these three values. So again the middle value is 8. Again 8 is still g greater than six. So
5:26:08
now we only have one value on the left of the 8 and right of the five. So uh which is already six. So immediately we
5:26:15
can find that value. And because we find both five and six to be existing. So 5 + 6 = to 11. We can simply return their
5:26:23
index values to be 2 and 3. So 2 and 3 is going to be the answer. In this case, if we see binary search actually works
5:26:30
pretty better than our brute force approach. Why? Because if we see if we try to calculate the time complexity in
5:26:36
this case, the time complexity is actually going to be big of n login. Why n login? Because in the worst case, we
5:26:43
might have to iterate over every single character in order to find the target value. And uh for uh us to find the
5:26:50
remaining value we have to do log and work. So again if we see this solution this solution is much better compared to
5:26:57
a brute force approach which had the time complexity of big of n². Uh now the question is is this the most optimal way
5:27:03
to solve this problem and the answer is no. There is still one more solution that can give us the answer in big of n
5:27:09
time. Okay. So the optimal solution I'm
5:27:15
proposing is actually using two pointers. So suppose this is the array input array we are given and we are
5:27:21
given the target value to be 13. Right? Now we already know that uh 6 + 7 is going to be the answer. But let's
5:27:26
quickly see the approach I'm suggesting. Basically we are going to have two pointers left and right. Now remember
5:27:32
all the values that are on the right side of this left pointer are actually greater than this value of left. Right?
5:27:39
And same way all the values that are on the left side of this right pointer is actually less than whatever the value at
5:27:45
right pointer we had. So the idea is originally we are going to do the sum of this left pointer and right pointer we
5:27:52
are going to compare that sum to this target value. Now if the sum is actually greater than target value which means we
5:28:00
need to lower the sum. How can we lower the sum? We can only lower the sum if we move this right pointer on the left
5:28:06
direction because remember all the values that are on the right that are on the left of this right pointer they are
5:28:12
actually less than this right pointer. So if we reduce the values automatically sum is supposed to go down and that
5:28:18
would lead us to that would lead us near the target value. Right? Again same way
5:28:24
if we identify that sum somehow is actually less than the target value. If sum is less than the target value which
5:28:29
means we will have to increase the value of the sum. How can we increase increase the value of the sum? By increasing the
5:28:35
value of the left pointer because all the values on the left pointer are actually greater and right pointer will
5:28:41
remain constant in that that case. And if we keep on repeating the same process
5:28:46
until we come up to the sum that equals to target value, eventually we would get
5:28:52
the two pointers located at the correct position that would lead us to the correct answer. Uh how? Let me quickly
5:28:58
show it to you. And by the way, let me also mark the indexes in this this case as well. So now we have our left pointer
5:29:05
and we have our right pointer and we have the variable sum. Right? Currently left is equal to 2 and right is equal to
5:29:10
42. If we see sum of these two, sum is actually going to be 44. 44 is definitely greater than 13. So because
5:29:17
44 is greater than 13, we have we will have to somehow reduce the values. So what we are going to do is we are going
5:29:22
to update the right pointer to move one point to the left side. Right? So now our new right pointer is going to be
5:29:28
this one. So now our right pointer value is 21. So 21 + 2 is still going to be uh
5:29:33
23. Now 23 is again greater than 13. So because of that we are going to shift our right pointer again. So now right
5:29:39
pointer is at 12. 12 + 2 is 14. 14 is still greater than 13. So again we are going to switch our right pointer. So
5:29:46
now right pointer is at position number 10. So now the right pointer value is 10. So now 10 uh 10 + 2 is equal to 12.
5:29:55
So 12 is not greater than 13 is actually less than 13. So now we will have to update our left pointer. So if we update
5:30:01
our left pointer, our left pointer is going to become value number five. Right? So now this value is 5. 5 + 10 is
5:30:08
again 15. So 15 is again greater than this value number 13. Right? So now
5:30:13
again we are going to switch our right pointer to go one point to the left. So now the right pointer value is actually
5:30:19
7. So if we do 7 + 5, 7 + 5 actually gives us the answer to be 12 right. So
5:30:25
now this 12 is still less than the value number 13. So because this is less than the value number 13. Again we are going
5:30:32
to update the value pointer of the left pointer. So now left pointer is at position number six. Right pointer is at
5:30:37
position number seven. 6 + 7 is equal to 13 which is exactly equal to whatever
5:30:43
the target value we had. And that is the correct solution. So now basically the positions of left and right pointer we
5:30:50
simply need to return that as the answer. So the answer in this case is going to be three and four. And this is
5:30:56
the correct way to solve this problem. Now what is the benefit of this approach? Well, if we see we are
5:31:01
actually computing everything in just single iteration. We are not doing multiple repetative work. So if we see
5:31:07
time complexity in this case the time complexity is actually going to be big of n which is a much better improvement
5:31:13
compared to our brute force approach and also our binary search approach. uh if we see space complexity in this case the
5:31:18
space complexity is actually going to be constant because we are not using any additional space apart from storing
5:31:23
couple of variables which is also a good sign. Now let's move on to the coding.
5:31:32
So first of all we are going to initialize the two variable left and right. Now we are going to run our while
5:31:37
loop that while left is less than right. Now inside the loop first of all we are going to check that whether the
5:31:43
combination of left and right if that is greater than the target value. So if that is the case we will have to reduce
5:31:50
the sum which means we will have to reduce the value of the right pointer. So right is going to become right minus one. Else if we are going to check that
5:31:57
whether the sum is actually less than the target value. If that is the case we are going to update our left pointer to
5:32:03
go one step to the right. That is not the case which means we are actually at the correct position. So we can simply
5:32:09
return uh the index values but remember we are presented with one
5:32:16
index array. So we are going to add one value to the left and right. And this was just the additional small complexity
5:32:22
they added to the problem otherwise it would have been too simple. And uh basically in this loop we are taking
5:32:28
care of everything. So we should have gotten the answer. If somehow we get out of the loop without returning the answer
5:32:33
we can simply return null that we were not able to find the answer and that should do the trick. Let's try to run
5:32:38
this code. Okay, seems like our solution is working as expected. Let's submit this code. And our code runs decently
5:32:45
efficiently compared to lot of other solutions in terms of time complexity. In terms of space complexity, it's actually pretty efficient because we are
5:32:51
not using any additional variable to store the sum. Uh and that's it. Uh let
5:32:56
me I will be posting this solution in the comments. So you can check it out from there. Thank you.
5:33:09
Today we are going to do threes someum lead code problem and it is a very interesting problem. If you see some of the companies where I want to get a job
5:33:15
who have already asked this question there are companies like Amazon, Microsoft, Apple, Facebook, Uber,
5:33:20
Bloomberg, Google, Tesla, Pans and LinkedIn. So that's why I'm paying my utmost attention. I hope you also enjoy
5:33:27
the video. So this is a lead code medium problem and also a very well-liked problem on
5:33:33
lead code. Basically we are given an integer array called nums and we need to return the triplets. Now we need to
5:33:40
return the triplets such that the sum of all of those triplets is actually equal to zero. And we are also given the
5:33:46
definition that the elements has to be unique. So I, J and K is supposed to be the triplets and they should not be the
5:33:52
same. They should be different values. We are also told that the answer set must not contain any duplicate triplets.
5:33:58
So this is an additional set of complexity that we will have to take care of. Now let's try to understand
5:34:04
this problem with couple of examples that are provided over here and I have actually broadened these examples. So
5:34:10
let's try to understand them. So suppose this is the input array nums we are given. We need to find the triplets such
5:34:16
that the sum of each of all the triplets is equal to zero. So if we see that in
5:34:21
this example we can actually find the sum of these three values to be zero. So first of all we are going to add these
5:34:27
three entries into our answer that minus1 0 and 1. Uh this triplet equals
5:34:32
to 0. So we can add that to our answer list. A second triplet we can find is the value min -1 again -1 and value + 2
5:34:40
because -1 + -1 + 2 is also equal to zero. So again we can add it to our
5:34:47
answer set uh that 2 -1 and minus1 is the answer. Now apart from that we
5:34:52
cannot find any more triplets. So this this is the only answer we are going to return. One critical thing to understand
5:34:59
over here is that this minus1 is actually using two times uh in two different answers. That is perfectly
5:35:05
fine. But we cannot have an answer where we already have the value like minus1, 0
5:35:11
and minus1 and again we have the value minus 1, 0 and + one. This should not be the answer. So this is one of the
5:35:17
conditions that is given. Uh second condition is that all the values of i, j and k has to be unique. they are located
5:35:24
at unique positions because we cannot use the same value again and again. We cannot do something like 0 + 0 + 0 equal
5:35:30
to 0 and return that as the answer of the triplet because in this case we only have one zero not three zeros. So just
5:35:37
keep all of these things in mind. If we take a look at the second example over here we actually do not have any pair
5:35:43
that equals to zero. Right? So in this case we are only going to return an empty array as the answer. And basically
5:35:49
this is what the problem is asking us us to solve. Now there can be two potential solutions for this threesome problem
5:35:56
that we are trying to deal with. Uh first solution is actually a twosome problem solution that is also another
5:36:02
lead code problem where we use hashing to generate the solution for this twosome problem. Uh second solution is
5:36:08
two sum two problem where we actually use two pointers to come up with that solution. And in this case we are going
5:36:14
to see that how using hashing we can solve this threesome problem or how using two pointers we can solve this
5:36:20
three threesome problem because both of this concept can be useful. Uh we can choose either one of them. Now I'm going
5:36:27
to show you the theoretical knowledge of both the problems but I'm only going to show you coding for this twosome two
5:36:33
problem. Uh let me know in the comments if you want to see the code for this twosome problem as well and I can uh
5:36:38
show it to you. Okay. Okay. So first let's see that what is going to be the optimal solution
5:36:44
using the solution we used in the twosome problem. Now if you want to know more about twosome problem you can check
5:36:50
out my video over here and that is going to give you much more clarity. Okay. Now let's get back to our question. So if we
5:36:57
suppose this is the original input that we are given and we are trying to find a set of triplets that sum up to zero
5:37:03
right which means we are trying to find three different values where i + j + k is equal to z. Okay that is the whole
5:37:09
idea. The technique we are going to use is that okay suppose this is the first value right suppose if we consider i is
5:37:15
equal to minus 5 once that is done what we will have to do is we will have to try to find that if j + k is equal to +
5:37:22
5 if that exist inside this remaining array if that is the case then we would
5:37:28
actually have a triplet called i + j + k that sums up to zero because i is equal
5:37:33
to minus 5 j + k is equal to + 5 and now we simply need to see that inside the
5:37:38
remaining array do we have a pair j + k that is equal to + 5 and that was actually the original question for this
5:37:44
twosome problem. So that is how everything is linked internally. The idea is okay that we can find it easily
5:37:52
using a hashmap or a hash set and then we would be able to get this answer. The problem that would come in this case is
5:37:58
that because we are trying to avoid duplicates and what would happen with this approach
5:38:04
is that okay suppose if we consider i is equal to minus 5 right we would actually have an answer where the values of
5:38:10
minus5 0 and + 5 exist as one of the answer and we are able to generate this
5:38:15
okay so now we are able to say that okay this minus5 we have already taken care of and we found the correct answer but
5:38:22
if we look somewhere inside the remaining array we would also find another minus 5. So when we try to
5:38:28
repeat the same logic basically even for this minus5 we will also have the i is
5:38:33
equal to minus 5 we will try to find j + k is equal to + 5. Then again we would have another answer that also looks like
5:38:40
-5 0 and 5. And remember these is going to be the duplicate value that we are
5:38:46
trying to avoid. So in order to make our lives easier what we can simply do is if we take this input array and if we sort
5:38:53
this input array and because if we when we sort this input array we are going to have the same looking values right next
5:39:00
to each other. So we can only have a condition that the moment we find out that two adjacent values they are same.
5:39:06
If that is the case that if we find the two adjacent values to be the same then we are simply going to ignore that case
5:39:12
and move on to the next value. Okay. So now after this whole explanation uh let me clean this up a bit and uh create the
5:39:18
sorted array. So now we have our sorted array right now we are trying to we will try to see
5:39:24
that what could be the potential I J and K values. Now based on the I value we will also have to determine that what
5:39:30
should be the J + K value and based on the J value we also have to determine that what should be the K value. Right?
5:39:36
That is how we are going to do the things. So first let's try to see that if I is equal to minus 5. If I is equal
5:39:42
to minus 5, we will have to find J + K is equal to + 5. If we have to find J + K is equal to + 5, we'll try to start
5:39:48
iterating over this remaining array. Again, we are going to create a hash map or a hash set over here. So, let's
5:39:54
create a hash set first. Okay. Now, we are going to start iterating over all
5:40:00
the remaining values. Okay. So, suppose this value is minus 5. So, we'll try to consider J to be minus 5. If J to J is
5:40:05
equal to be minus 5, then K has to be + 10. And now we are trying to see that
5:40:11
okay we'll see that if this k is equal to 10 exist if that is the case we will return that if it does not exist we are
5:40:17
going to add that value to our hashmap. Okay. Okay. So because k is equal to 10 does not exist we will have to add all the values to our hashmap. And remember
5:40:24
that is a property of a hash set where it does not exist duplicate values. So we will only have unique values inside
5:40:29
over here. So since j is equal to minus5 didn't work. We'll try to see that whether j is equal to minus3 works or
5:40:34
not. So if J is equal to minus3 then in that case we will need the k value to be + 8. Uh + 8 also does not exist and we
5:40:42
can look that up immediately because of this hash set. Right? Now we will try to find another value. Okay. So if that
5:40:48
didn't work we will try to see that whether j is equal to 0 works or not. Okay. So if j is supposed to be zero
5:40:53
then the value of k has to be + 5. Okay that we can look up immediately and we
5:40:59
would be able to find that k is equal to + 5 already exists inside our hashmap. So immediately we found that we are
5:41:04
actually going to have an answer list where we are going to populate the values of i, j and k we found. Okay. So
5:41:10
we are going to add the values minus 5, 0 and + 5 immediately. Now we are going to repeat the same process for the all
5:41:16
the remaining values. Right? So and for every single value we will also have to
5:41:21
create the new hash set and new i, j and k values. So we will empty this one.
5:41:26
Okay. Now the new i value is actually minus one. The thing is this is a track
5:41:32
because we already had a value minus 5 that we already iterated over. So we will not have to use this one and that
5:41:39
is how we are going to avoid duplicates. Now suppose if next I value is minus 3. Okay. So if I value is minus3 then J + K
5:41:46
has to be + 3. Okay. So if J + K has to be + 3. Let's see that what could be the potential remaining J + K values over
5:41:53
here. Okay. So over here currently J value is zero. So if J value is zero then K value has to be + three. Okay. So
5:41:59
we'll try to see that inside the remaining array whether plus three exist or not. Plus three does not exist. But
5:42:04
that is going to help us fulfill our hash. So we are going to add all the entries to our hashmap. And uh we
5:42:12
couldn't find k is equal to 3. So now we are going to try the new value of j. J is equal to zero. So again because this
5:42:19
zero we already consider for j we should not be considering this zero. So we can just simply jump over. Okay. So now next
5:42:25
value is j is equal to 1. If J is equal to 1, we will try to see that whether K is equal to 2 exist or not. And K is
5:42:31
equal to 2 already exist that we can clearly see over here. So because it exists, we are actually going to have J
5:42:37
and K values properly set up. And uh we are also going to add one more triplet to our answer that is minus 3 1 and 2.
5:42:45
Okay. Now we can ignore this one. Okay. Now current I value is zero. Okay. If I
5:42:50
value is zero, then J + K has to be zero. Okay. So now we are we'll try to
5:42:55
find J + K to be zero. Now uh inside the current method okay now this next value
5:43:01
of J potential value of J uh this is the zerooth value. So we'll try to add this
5:43:07
value and by the way I forgot to clear the hash but it would be cleared. Okay. Now if J is equal to 0 then K also has
5:43:14
to be zero. Okay. So currently K is equal to0 does not exist inside the remaining array. So because it does not
5:43:19
exist we'll try to jump onto the next value of J. if if j is equal to 1 can
5:43:24
work or not. So if we try to put j is equal to 1, it is definitely not going to work and we won't be able to find a
5:43:30
pair j + k is equal to 0. So i is equal to0 is also not going to work because i
5:43:36
is equal to0 not going to work. Uh and um uh and we are we have already taken
5:43:41
care of this zero. So which means we don't have to see for this zero. Now we'll try to see that whether i is equal
5:43:46
to work or not. But the question is do we really want to check whether I is equal to work one is going to work or
5:43:52
not because inside the remaining array all the values are actually going to be positive values. So because these values
5:43:58
are going to be positive values J + K is always going to increase the value of whatever the sum of I J and K is going
5:44:05
to be because this I is positive. So immediately we can stop our search and whatever the answer we have found we can
5:44:11
actually return that as the answer and that is the whole approach. Now and if we see time complexity in this case the
5:44:17
time complexity is actually going to be big of n log n that is to sort the array
5:44:22
plus big of n² why because for any single i value we will have to find j
5:44:28
and kth value which means for every single one of them we will have to iterate over the entire list of all the
5:44:34
arrays. So that takes like big of n square and that is the best we can do. If you see space complexity, space
5:44:39
complexity is also going to be big of n because for this sorting operation, it takes big of n time and plus we are also
5:44:45
creating this hash. So that also takes big of n space.
5:44:54
Okay. Now we will try to see that what is going to be the optimal solution using the two sum two problem. Now if
5:44:59
you want to learn more about this problem, you can check it out my video over here and this is a very good explanation for that. Now uh we are
5:45:06
going to use the same example as the input and as mentioned for the reasons explained before basically we are going
5:45:12
to use the sorted array in this case as well. So from this original input we are actually going to create a sorted array
5:45:18
first. So that is going to help us avoid duplicates. Now the again idea is that currently we are going to consider the
5:45:23
one value to be I. Okay. So suppose we are going to consider I is equal to minus 5. If that is the case, J and K
5:45:30
value could be po potentially possible where J + K is equal to + 5, right? And
5:45:35
inside this remaining array, we will have to find the + 5 value. So, what we are going to do is we are going to
5:45:41
initialize couple of variables. Uh, so first is going to be left pointer and second is going to be right pointer.
5:45:47
Now, every time we are going to do left plus right. If left plus right is equal to five, then basically we are good. Our
5:45:53
life is set and we can simply add it to our uh J + K values. If that is not the
5:45:58
case, if we somehow find that left plus right is actually greater than five. If that is the case, then somehow we will
5:46:05
have to reduce the sum of this left plus right. How can we reduce the sum of left plus right by shifting this right
5:46:11
pointer on the left hand side. Why? Because all the values on the left of this right pointer are actually less
5:46:17
than whatever this right value we had. And uh if somehow we identify that okay
5:46:22
this left plus right is actually less than the answer five. If that is the case, we are going to update our left
5:46:28
pointer to go one step on the right side. So then we would be able to increase the sum that we are trying to
5:46:34
achieve. And that is how we would be able to generate the correct J and K values. So let's try to see the approach
5:46:40
in action. So suppose currently the I value is equal to minus 5. Okay, I is equal to minus 5. J + K is equal to + 5
5:46:46
we are trying to find. So once we have the J + K value we are trying to find we are going to initialize two variables
5:46:52
left and right. Okay. So currently our left pointer and right pointer we are going to be concerned with that and we are also going to be concerned with left
5:46:58
plus right sum and uh how that is referring to whatever the value we are trying to find. Okay so currently the
5:47:05
target value is five. Okay now the current left position is minus 5. Current right position is + 5. So left
5:47:11
plus right is equal to 0. 0 is actually less than minus 5. So because 0 is less than minus 5 we will have to update the
5:47:16
value of our left pointer to go one step on the right. So now the current left pointer is minus 3 minus 3 + 5. So if we
5:47:23
do minus 3 + 5 the value we get is 2. 2 is still less than five. So because 2 is less than five again we are going to
5:47:28
update our left pointer. So now the left pointer is at zero position right over here. Uh and uh currently the sum we are
5:47:35
going to get is that okay this is zero. This is five. So 0 + 5 is equal to 5. So currently left plus right is equal to 5.
5:47:42
Five is exactly what we are looking for based on this uh remainder value we have
5:47:47
created. Okay. So now this left pointer can be assigned to this J value and
5:47:52
right pointer can be assigned to this K value and we can actually populate our answer. So inside our answer we are
5:47:58
going to have the first entry called minus 5 0 and + 5 as one of the answer. Okay. Now we are done with taking care
5:48:05
of this minus 5. So now we'll have to take care of this another value. But again same thing this value is also
5:48:11
minus5 same as the previous value. So again we are going to ignore this case as well. And now currently our I is
5:48:17
going to be minus 3. Okay. So now if we put our I to be minus 3. Uh our J + K
5:48:22
sum has to be + 3 in this case. Okay. So J + K has to be + 3. Again if J + K has
5:48:28
to be + three, we will also have to update our left and right pointer. So currently left pointer is also going to
5:48:34
be at the position zero. Right is going to be position number five. Okay. And we will also have to update this value as
5:48:39
well that this has to be three. Okay. Now uh currently 0 + 5 is actually five.
5:48:45
Five is actually greater than three. So because five is greater than three, we will have to reduce the value of our right pointer. So currently our right
5:48:51
pointer is going to come over here. So now the right pointer value is actually two. Okay. So if we do 0 + 2, 0 + 2 is
5:48:58
actually going to be three. So three uh sorry. So now if we do 0 + 2, 0 + 2 is
5:49:04
actually actually going to be 2. 2 is now less than whatever the value of 3 is. Because of that we will have to
5:49:09
update our left pointer to go on the right side. Now the moment we do that, okay, this value is also zero. Same as
5:49:14
the previous value. So because of that because we have already calculated this zero we are actually going to ignore
5:49:20
this zero as the left pointer and our left pointer is going to come over here. Okay. So now the value of our left
5:49:25
pointer is actually 1. So 1 + 2. So 1 + 2 is actually three and three is what we
5:49:31
are looking for that we already find the answer. So we are also going to populate the values of left and right over here.
5:49:36
And inside the answer we are going to have one more entry called minus3 + 1 and +2. Okay. Now uh uh okay now we have
5:49:43
taken care of all the cases. Now again this value I is equal to0. If I is equal
5:49:49
to0 we will not be able to generate the answer. And now in this case I is going to be one. So that is going to be the
5:49:54
positive value. So because of that we are actually going to break out of it. And simply whatever the answer we have
5:50:00
found we are able to return that as the answer using this two pointer solution. And even for if we see the time and
5:50:06
space complexity in this case the time complexity is also going to be big of n² plus bigo of n log n. Why? Because we
5:50:14
will have to do the sorting operation. If we see space complexity the space complexity is also going to be big of n
5:50:20
that is going to depend on the implementation for the sorting we are using. Uh so that is how we are able to
5:50:27
generate the solution. If you see in this case we are actually not using any additional h set. So that is a plus
5:50:33
benefit in my opinion and if you show both the approaches in in any interviewer would be like more than
5:50:38
happy with you. So first of all we are going to sort the
5:50:45
given input nums and we are also going to create a new variable called result to store the list of list that is needed
5:50:52
over here. Now we are going to run a for loop across the given input nums. Notice
5:50:58
inside the for loop we are only running it up until the point where the value of nums of i is actually less than zero. Uh
5:51:06
and the moment it gets greater than zero there is no point in continuing with the loop. So we just simply ignore that. Now
5:51:11
inside the loop we are actually going to call our two sum two function. But for that we actually have couple of
5:51:17
conditions that we are going to take care of. So first condition is that if the given value of I is equal to zero or
5:51:22
the starting position then we do it or we check that whether the two adjacent values of I and I minus one are they
5:51:29
same or not. If they are not same then only we call our two sum two function otherwise we ignore that particular
5:51:35
entry. Inside the method uh we are going to call the two sum two method uh where we are going to pass in the value of the
5:51:41
given input integer nums the current i position and the result uh variable and
5:51:48
basically that's it. Once this for loop ends basically by with the help of this two sum two method our result should
5:51:54
have been populated. So we can simply return the result. Now it's time to create the new two sum two method. First
5:52:01
of all, we are going to initialize two uh pointers called left and right. Now, we are going to have our while loop that
5:52:07
while left is less than right, we are going to do some interesting things. First of all, we are going to have a variable called sum that is going to
5:52:14
calculate the current total sum. Now, we are going to check that if the given sum if that is less than zero, if that is
5:52:21
the case, we will have to increase the value of the left pointer.
5:52:27
Else if we are going to check that if the given sum is greater than zero. If that is the case then we will have to
5:52:34
reduce the value of our right pointer. If both are not the cases which means our current sum is exactly zero. So
5:52:41
first of all we are going to add a new entry to our result uh variable that we have created. After adding the values to
5:52:48
the result, we will again have to update our left pointer until the point that
5:52:53
whether the two adjacent values of left pointer they are same or not. Basically
5:52:59
that's it. This should have taken care of all the scenarios and uh this should be working. Now let's try to run this
5:53:05
code. Okay, seems like our solution is working as expected. Let's submit this code.
5:53:12
And our code runs decently efficiently.
5:53:23
Today we are going to do container with most water lead code problem. And if you see some of the companies where I want to get a job who already asked this
5:53:30
question there are companies like Amazon, Apple, Google, Microsoft, Facebook, Goldman Sex, Bite Dance,
5:53:35
Bloomberg, Tik Tok, Uber and Tesla. So that's why I'm paying my utmost attention. I hope you also enjoy the
5:53:41
video. This is a lead code medium problem and also very well-like problem on lead
5:53:47
code. And like any lead code problem, we are given some input and we are expected to get some results uh from this
5:53:53
particular input. But before we start understanding this problem, uh first let's see this concept that I'm trying
5:53:59
to explain. Okay. So suppose we are given a container that looks like this and we are trying to see that how much
5:54:05
water can we fill in this container. Well, the logic is actually quite simple. We can only fill water up until
5:54:12
this point inside this given container. Uh anything more if we try to add water
5:54:18
over here that water would simply spill out. We won't be able to fill our water above this line. So that is a given fact
5:54:24
right? That is a very simple explanation. Now if I ask you that how much water is present in this container.
5:54:31
So then in that case the answer is simple. There can only be water up until this point. Nothing more than that. So
5:54:38
in this case for this particular container rather than considering this container to be a container if we
5:54:44
consider this to be a rectangle things becomes easy for us because we know that
5:54:50
uh the surface area of rectangle is the amount of water we can store in this particular container and we know the
5:54:57
formula to calculate the area inside any given rectangle. Suppose this is the height of the container and this is the
5:55:03
width of the container. If we are given these two values basically if we do h * w height crosses height multiplied by
5:55:10
width we will get the amount of area and that would equivalent that how much water we can hold in any given
5:55:16
container. Now let's try to understand another scenario. Suppose we are given a container that looks like this or we are
5:55:23
given a container that looks like this. In these two cases how much water can we store? Well the answer is again simple.
5:55:30
we can only fill water up until this point till the lower edge on on any
5:55:35
given container not more than that. So now in this case we are actually given two different heights for each sides of
5:55:41
the given container right. So suppose this side is h1 and this side is h2 and same goes over here this one is h1 and
5:55:47
this one is h2. If that is the case if we try to calculate the area in this case the area equation for the water is
5:55:54
going to change. Why? because we are not going to use h1 over here because this is the higher side. We are actually
5:56:00
going to use h2 which is the lower side. So in this case uh the area is going to be h2 * width for this particular
5:56:08
container. But for this particular container the equation is actually going to be h1 * width because this h1 is
5:56:16
actually smaller in this case. So these are the two concepts that you will have to understand and now let's go back to
5:56:21
the problem. Okay. So now in the problem we are actually given an array called
5:56:27
heights of length n and now if we try to plot this array of height in on a graph
5:56:34
we can consider that based on the x-axis we can actually create a container and
5:56:39
then we need to find that what is the container we can create that contains the most amount of water and then we
5:56:44
need to return the amount of water that the maximum container can store. Now I know that the wording may sound
5:56:50
confusing. So it would be better by understanding with this example. Suppose we are given an array heights like this.
5:56:56
So if we try to plot this array heights on a graph, we can actually get a graph that looks like this. Now in this graph
5:57:03
you can see that there is a difference between lines and based on these line differences we can actually create some
5:57:11
sort of containers between any two vertices. uh and the amount of water we can fill depending will depend on the
5:57:18
lower side of the height rather than higher side of the height. So in this case we can actually create a container
5:57:23
that looks like this. So if we try to consider this index number one and index number four uh the container we can
5:57:29
create is going to look like this where this is the amount of water we can fill nothing more than that. Now remember as
5:57:35
mentioned earlier that for every single time if we want to calculate that what is the amount of water we can find we
5:57:41
need to calculate the area of the presumed rectangle and for that we need the height which we already have based
5:57:47
on these values which we can derive from the array and we need the value of the width. So width we can achieve by
5:57:54
calculating the difference between any two places on the x-axis and these
5:57:59
values we can determine depending on the index values of the given input array. So it makes our lives easier. Uh so in
5:58:06
this case if we try to see that some of the containers that we can make we can make a container that looks like this
5:58:11
amongst these two values and then we can calculate its water. So I'm just showing you for an example. So in this case the
5:58:17
minimum height is actually five. So height is going to be five and the width in this case is actually going to be
5:58:22
two. So 5 * 2 we can say that okay there is 10 units of water we can put in this container if this was to be the be the
5:58:30
container. The thing is we are trying to find the maximum maximum water we can make amongst any
5:58:36
given container. So in this case the answer is actually going to be this container where the current height is
5:58:43
seven among 7 and 8. So we are going to choose 7 as the height. Okay. So h is equal to 7. So okay it's going to be 7
5:58:51
times the distance. So distance in this case okay this value is 2 and this value is 9. So distance is also 7. So in this
5:58:57
case 49 is the maximum unit of water we can contain and that is going to be stored between this container. Uh and
5:59:05
basically I hope that this makes understanding this problem easier. And after understanding the problem now
5:59:10
let's focus on different solutions that we can achieve. The first approach we have is a brute
5:59:16
force approach and suppose this is the input we are given. If we try to plot it on a graph we can actually create a
5:59:21
graph that looks like this. Now the idea is we are actually going to check every
5:59:27
single container that we can possibly make and depending on that we will try to see that what is the what container
5:59:33
contains the most amount of water. So basically we are going to have a two variable first variable is called area
5:59:39
to contain to calculate the water at any given container and second is going to be the max variable that is going to be
5:59:45
update its value whenever we find a better area or maximum water we can contain. Right? So first we will start
5:59:52
with this first index and we will try to see that okay what is the container we can make with between the index 1 and
5:59:57
two we can make a container that looks like this. What is the container we can make between 1 and three we can make a
6:00:02
container that looks like this. Uh and say so on and so forth we will keep on repeating our uh graph. After being done
6:00:08
with this value number one we will ignore that and we will start focusing from value number two. So from value
6:00:15
number two we can make container that looks like this and then again a container that looks like this and blah
6:00:20
blah so on and so forth and eventually we would find an answer in this case between this value number two and seven
6:00:27
indexes that the if we make this container that is going to hold maximum amount of water and in this case the
6:00:34
answer is going to be okay. So for this area height is going to be four because that is the smaller amongst these two and the width is actually going to be
6:00:40
five because 2 - 7 is five. So maximum area is going to be 20 and 20 is the
6:00:45
answer we are going to return. So this solution would work as expected. But if we see the issue with this solution, the
6:00:52
issue is actually time complexity. Why time complexity? Because for every single value we are comparing it with
6:00:57
all the other values to see what is the container we can create and we are not doing things efficiently. So basically
6:01:03
the time complexity in this case is big of n² which is very bad and we will have to do something better. So let's see
6:01:09
that what is the better approach we can get.
6:01:15
So for the optimal solution we are actually going to use two pointers to our advantage and we will try to see
6:01:21
that what is the optimal container we can make. So we are going to have a pointer left located at the first
6:01:27
position and we are going to have a pointer right located at the last position. The idea is both pointers are
6:01:32
going to come towards each other until they meet or cross each other. Now every single position we will try to see that
6:01:39
depending on the values of left and right what is the container we can make. Uh and then we will try to calculate its
6:01:46
area and after calculating the area we are going to compare the heights between left and right and whichever has greater
6:01:53
height uh we are going to keep that height and then we are going to update the remaining counter. So left counter
6:01:59
counter will go on the right side or right right counter will come on the left side. Uh so let's see the solution
6:02:05
in action and it will make more sense. So basically uh initially first if we see currently the height at left is
6:02:11
three and height at right is two. Okay. So if we want to calculate the area we are going to calculate the smaller amount. Okay. So currently the smaller
6:02:18
height is actually two. And if we see the width, width in this case is going to be seven. Okay. So current area we
6:02:24
are able to calculate is 14. We are also going to have a variable called max area. So currently the max area we have
6:02:30
been able to find is 14. Okay. So far so good. Now we will try to compare the heights between left and right. Okay. So
6:02:37
currently left height is actually greater. So it is in our interest to move right counter one step to the left
6:02:44
rather than moving the left counter. Okay. So in this case right counter is going to come at come over here. Now
6:02:49
again we are going to repeat the same process. So now currently the height at right counter is six and left counter is
6:02:56
three. Okay. So now if we we will have to calculate the area again. So we are going to choose the smaller value amongst the height. So currently this is
6:03:02
going to be three as the smaller height and width is going to be six. Okay. So currently the area we can get is 18. 18
6:03:08
is greater than 14. So we are going to update the maximum area maximum water we can contain to 18. Uh now we are going
6:03:15
to compare the height between left and right. Now in this case the height at right is actually greater than left. So
6:03:20
we are going to update our left pointer to go one step to the right. Uh now this left pointer is located over here.
6:03:27
Currently the height is two. Again we are going to calculate the area. So this height is actually going to become 2 and
6:03:33
the width is actually going to become five. So 2 * 5 is actually 10. Uh so because 10 is less than 18 we are not
6:03:40
going to update the maximum value we have been able to find. Again we are going to calculate the heights between left and right. So again right height is
6:03:46
greater. So we will update the left pointer to go on one step on the right side. Uh now currently the height over
6:03:52
here is seven and uh currently the other height is six. So we are going to choose the smaller height. So the height we are
6:03:59
going to choose is going to be six. Uh six times the width is going to decrease. Okay. So currently the width
6:04:05
value we have is going to be okay. This is uh okay this is left pointer. So 3 - 1 4. Okay. So uh 6 * 4. So this area
6:04:13
becomes 24. 24 is actually greater than 18. So because 24 is actually greater than 18. We are going to update the
6:04:19
maximum area we have been able to calculate. Okay. So this is 24. Now again we are going to compare the
6:04:25
heights between the left pointer and right pointer. So currently right pointer is actually less. So now we will have to update the value of the right
6:04:32
pointer. So currently this becomes our right pointer. Now this value is three. This value of left pointer is 7. So
6:04:39
again the height is actually going to be three and the width is going to be three as well. So this is going to be 3 * 3.
6:04:45
So this is 9. We do we don't need to update the max value. Again if we compare the heights the right is
6:04:50
actually smaller. So again we will update the value of the right counter. So now this time the right counter is
6:04:56
reaching at this value number one. So if we calculate the this container this container the uh area is actually going
6:05:02
to be two. So 2 * 1. So 2 * 1 is only two. So we don't need to do anything
6:05:08
again. We will update the right counter. So currently the value of right counter is four and the left counter is 7. Okay.
6:05:14
So we are going to have a container that looks like this. So 4 * 7 uh sorry uh 4
6:05:20
* 1 is going to be four as well. Uh so then we in this case we don't need to
6:05:25
update the max value and if we try to update the left or right variable again that they would cross each other. So
6:05:31
because they would cross each other now we can end up get out of our loop. So whatever the maximum result we have
6:05:37
found so far that is going to be the solution we need to return. So in this case the answer is actually going to be
6:05:43
24 as that this is the maximum units of water we can contain between basically
6:05:49
this container this water container and uh that is the answer we need to return. Uh if you see the beautiful thing about
6:05:56
this solution uh this whole solution gets completed in a single iteration between these two pointers and if we see
6:06:03
time complexity in this case the time complexity this is actually going to be big of n only which is much better improvement compared to our brute force
6:06:09
approach which had the time complexity of big of n square which was really bad. So we can avoid that. If you see space
6:06:15
complexity the space complexity is also really good because apart from using couple of pointers we are not using any
6:06:20
additional space. So space complexity is actually constant space which is wonderful and uh this is a very good
6:06:26
approach and a very good way to learn two pointer problem and uh I hope you understood it. Now let's move on to the
6:06:32
coding. First of all we are going to initialize
6:06:38
couple of variables. So first variable is going to be max and that is that we are going to initialize it to zero. uh
6:06:44
then we are going to initialize two pointers left and right and left is going to have the value of zero and
6:06:49
right is going to have the value of whatever the length of heights array is. We run our while loop that while left is
6:06:55
less than right. Now first of all we will have to calculate the width. So width is going to be right minus left.
6:07:02
So now we have the width and we already have the height from this heights array. We will calculate the area. So this uh
6:07:09
equation should give us the area. We are selecting the lesser height amongst right height and left height. And uh now
6:07:16
we will see that whether we need to update the max value as well. And now we will have to update our left or right
6:07:22
pointer. So we will check that okay if the current height of left is that is less than or equal to the right height.
6:07:29
We will update the left counter. If that is not the case we will update the right pointer to go one step on the left side.
6:07:35
And uh in the end we can simply return the max variable that we have calculated.
6:07:41
And that should be it. Let's try to run this code. Okay, seems like our solution is working as expected and our solution
6:07:47
runs pretty efficiently compared to lot of other solutions. And I will be posting this in the comments so you can check it out from there. Thank you.
6:08:00
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. We are going to do trapping rainwater problem today.
6:08:07
And uh if you want to see that what are the list of companies that have asked this question that comes later in the video. So you can directly check it from
6:08:13
there. Uh let's understand the problem statement. We are given an array of array called n where all the integers
6:08:19
are non- negative and any single integer represents actually the height at that particular position inside the array. We
6:08:26
are given that the width at any two positions is actually one. So we can
6:08:32
consider that and we need to see that how much water can we trap when it rains. We know that it's going to rain a
6:08:38
decent amount. So we can we all the cells that could trap water would trap
6:08:43
water. Now and our aim is to see that what is the maximum unit of water we are going to store. So let's try to
6:08:50
understand this with an example. Uh over here we are given an elevation graph and
6:08:55
all of those values are represented as uh bars inside the given graph. And we
6:09:02
notice that because there are some height differences uh due to the height
6:09:07
difference there exist an empty space inside this given input and because that
6:09:13
empty space exist uh rain water can actually fall in and be stored uh on
6:09:19
those particular positions. So if we see over here like this first position is actually zero but and suppose the rain
6:09:26
falls can any water be stored over here? Well, it cannot be stored because in
6:09:32
order for water to be stored, we need a vessel like this or like this or something like this where at least water
6:09:39
can be stored. Like over here, if we see water can be stored for all of these positions because all these three edges
6:09:46
were covered with some sort of solid material. Same goes over here. Like over here, we can only fill water up until
6:09:53
this point because on the left side, the edge is only up until this point. uh not
6:09:58
more than that like though on the right side the edge is actually higher but if we try to fill in more water or if rain
6:10:05
falls and more water falls on top of it all the water is going to spill out and no amount of water is going to be
6:10:12
stored. So that is one key important part is to understand that how water is stored and second is that we need to
6:10:18
iterate over this given input height and uh at every single position we are going to basically calculate that how much
6:10:26
water can be stored due to this height difference. So if we see in this example
6:10:31
at this first position no water can be stored. So like there is no there is no
6:10:37
water pointed uh with over here like this is a bar by itself and in this
6:10:43
particular bar um this is the boundary that is a solid surface that cannot
6:10:49
store any water and we cannot store any water on top of this one because
6:10:56
all the water that gets stored on top of this one will also spill out because on the left side the boundary is actually
6:11:03
non non-existent. Now if we look at this third position over here actually because of there
6:11:10
exist a height difference between these two positions we have a scenario something that looks like this where
6:11:18
water when the rain falls. On the left side we have a height of we have a bar
6:11:24
of height one which is represented over here and on the right side we have a bar
6:11:30
of height two which means that we are creating some sort of value over here where on the left at this particular
6:11:37
position on the left side the bar is actually of one size. So this is of one size and this is bar of two size. So
6:11:44
this is actually two size which means that there is exist an empty vacuum where water can fall in and water can be
6:11:51
stored. So this becomes our point and we can check that over here we can store
6:11:58
one unit of water. Now the question comes that why can we only store one unit of water? Why cannot we store more
6:12:04
than one unit of water? The formula is actually quite simple. Like at this
6:12:10
particular position we see that on the left side there exist some height on the
6:12:16
right side there exists some height. So suppose this one is left height, this one is right height. There are two
6:12:22
heights that exist at any moment and this by itself can have some height uh
6:12:27
as mentioned in this input that there can be some height that can be located
6:12:33
this position and suppose this position is actually the height we are currently
6:12:39
at. So we just name it as height. Okay. Now how can we determine that in this
6:12:44
scenario in this scenario if we see those all these values so left height is actually
6:12:51
one okay right height is actually uh two
6:12:56
and the height we are currently at which is this position is actually zero and
6:13:02
over here we were able to store only one unit of water. So why we were only able
6:13:07
to store one unit of water? Basically we were following this condition that first of all we need to check that what are
6:13:14
the bar height difference between on the at any given position on the left hand
6:13:19
side and and the at the right hand side and we need to take the minimum out of both of them because over here though on
6:13:26
this right hand side the bar is actually of height two units because on the left
6:13:31
hand side the bar is only of a height one unit. We cannot store water more
6:13:37
than this height because the water is going to spill out. Now that is one condition. Now second condition is in
6:13:44
this case we got lucky that over here there is no height at all. So that's why
6:13:49
we were able to store one unit of water over here. So basically we can we can say that at any given moment the amount
6:13:57
of water we can store in one unit is actually following this formula that the minimum of whatever the right height is
6:14:05
whatever the left height is. So whatever the lower value of both of these minus
6:14:11
the height we are currently at and if this is greater than zero then only we
6:14:18
can say that we can store some water at any given position like let's let's say
6:14:23
for an example that y at this first position we cannot we are not able to fill out any water and if we see both if
6:14:29
we see the if we see both the values so on the left at this particular position
6:14:35
I'm referring that on the left side the height left height we had was actually
6:14:41
zero the height at current position was also zero and the right height was
6:14:48
actually one. So if we apply this formula we can clearly see that on the
6:14:54
the amount of water we can fill we can or we can try to fill in this paste is
6:14:59
actually going to be minimum of these two. So minimum of left height and right
6:15:04
height is actually zero minus the height we are currently at. So current height is also zero which means that we cannot
6:15:12
store any water or we can store zero units of water at this particular position
6:15:17
or at this part this first position because
6:15:22
there exist height difference and same formula can be applied for all these places to calculate that what is the
6:15:30
amount of water we can store like if we see over here the bar height is actually two. Now for this particular position if
6:15:38
we want to check that what is the amount of water can be stored we know that over here we can store one unit of water and
6:15:43
why we are storing one unit of water is because if we see the left height over
6:15:48
here that is two. Now on the right side the right height there is no right
6:15:55
height over here. There is no right height over here which is greater than this one like this. There is some right
6:16:02
height over here but that is less than this height. So there is no point in us to treat it as valley up until this
6:16:08
point. But over here we know that the height is actually greater than whatever height we currently had over here. So
6:16:14
this right height is actually three. So we are going to check so we are going to apply the same formula. So we are going
6:16:20
to check the minimum out of 1 and three uh sorry one minimum out of uh two and
6:16:26
three. So this is left height this is right height and we are going to minus
6:16:32
whatever the height we are currently at. So current height is actually 1 and if we apply this formula we get 2 minus 1.
6:16:39
So we get one which means that over here we can store one unit of water. Now let's try to understand this one with
6:16:45
another example and I'm spending lot of time in this one because this is the actual crux of uh the entire
6:16:53
example. So over here if we want to calculate that how much amount of water we can store we are again going to
6:16:59
repeat the same process. So what is the left maximum height we can find for this
6:17:05
particular uh unit? Like the left maximum height we can find is actually two units. Uh so we can say the left
6:17:12
height is two. The right height is this one. So right height is three and minus
6:17:18
whatever the height currently we have at this position. So this position we don't have any height. So which is zero. So if
6:17:24
we apply the same formula we can get 2 minus 0. So we can say that over here we can actually store two units of water
6:17:31
and which is what is presented over here like that's how we can store one unit of water over here and that's how we can
6:17:38
store one unit of water over here. So at any given position for any particular
6:17:43
element we are only going to need two things because height we are already given. So we remember that in this
6:17:51
equation we are actually comparing three items. the right maximum height, left maximum height and height we are
6:17:58
currently at. So height we we already know and our aim is to find that how can we find this right height max right
6:18:05
maximum height at any given element left maximum height at any given any given element and uh then it would be piece of
6:18:12
cake to for us to identify that how much water can be stored at any particular position.
6:18:22
So we can have a brute force approach where at every single position we iterate over the entire left array and
6:18:27
entire right array and we find that what is the maximum left height we can find at any given position. We can also find
6:18:34
what is the maximum right height we can find at any given position and we already know that what is the height we
6:18:39
are currently at. And once you have both of this information we would uh calculate our result and uh we would try
6:18:45
to calculate our output. The thing is if this scenario is pretty darn bad like at
6:18:51
any single position. So even over here we will have to iterate over the entire left uh array and entire right array in
6:18:58
order for us to calculate these two values. And yeah this is brute force. So brute force is tend to be dumb like we
6:19:05
are not doing anything clever over here. So that's why we would end up with the time complexity of big of n² because at
6:19:12
any single position we are going to iterate over the entire array to find these two values left height and right
6:19:17
height. Now can we do something better over here and uh how can we find a
6:19:22
better approach like so so for the given input example we can
6:19:28
actually do something clever. What we can do is uh whatever the input we are given we can actually iterate over it
6:19:34
from the left side and at every single position we can see that for any any
6:19:40
single element what is the left me leftmost value or left max value we can store. Again we are going to iterate
6:19:46
over the given input example on the reverse order and then we can find that at any single position what is the right
6:19:52
max value we can find and then it becomes pretty simple for us. We can just simply apply this formula on the
6:19:59
entire uh input uh that what at any single position. So at any single
6:20:05
position we only need to find the minimum value of right max and left maxus
6:20:10
whatever the height we are currently at. And if this becomes greater than zero then we will add it to our whatever the
6:20:16
output we have and this would be our answer. So let's iterate over first uh
6:20:23
on the left max side on this given input. So on the first element the maximum left height can be zero. Over
6:20:29
here it can be one. Again over here it can be one. Uh now over here this value
6:20:35
is two. So left max left max height at this position would actually be two. uh
6:20:41
this would actually be one but thing is we we already find a greater value. So again we are going to keep it as two.
6:20:47
Again we are over here this one is zero. So again we the left max height we can find is two. Uh over here this one is
6:20:54
one. So again this would be two. Now this is three. Which means that left max height we can find is actually three. Uh
6:21:00
this is two. So left max height we can find is actually three. Uh again three.
6:21:05
Again three and again three. So this is how we can fill out this left max uh
6:21:11
table. Same way we are going to fill out the right max table but we are going to do it in the reverse order. So over here
6:21:17
the right max edge is actually one and we are going to repeat the same process.
6:21:23
Now we have both of these tables filled out. It becomes pretty easy for us to find the solution and we can actually do
6:21:29
it everything. Now this approach would work perfectly fine. The thing is what is the issue with this approach? Like uh
6:21:35
if we calculate the time and space complexity, the time complexity for this one is actually big OO of uh n because
6:21:41
we are every we are doing everything in just a single loop and we are running this loop three times. Like first we are
6:21:48
running this loop so we are doing n work again we are running this loop so we are doing n work again and then we are
6:21:54
running the n work to find the output. But thing is uh still time complexity is going to be big of n and the space
6:22:01
complexity for this one is actually going to be big of n as well because we are storing these two additional data
6:22:08
structures. So this is much better improvement than our brute force approach where in the brute force we are
6:22:14
doing everything in big go of n square time. Uh so we are gaining significant improvements over here.
6:22:22
Now this question has been really popular with a lot of different companies and if we just look at the number of companies that have asked this
6:22:28
question and if we just see the amount of frequency that they have been asking this question I wouldn't be daring to
6:22:34
skip this problem like even if you see up until 2 years almost all the companies that are like one of the
6:22:40
biggest companies in the world they are continuously asking this problem uh just look at the numbers like Amazon Facebook
6:22:46
Goldman Sachs Bloomberg Microsoft Google Adob Uber Apple, Tesla, Lyft, Expedia,
6:22:54
Morgan Stanley, Swiggy, uh, Bite Dance, Data Bricks, Walmart, Flipkart, Service
6:23:00
Now. These are the companies that pay you in gold bricks and getting job or
6:23:06
getting employed at any of these companies at least for 2, three, four years is going to change your financial situation drastically. like you it's
6:23:12
going to be 180° turn and you only need to clear the technical interviews just once like after that you are sitting on
6:23:20
top of gold. So if you are also dreaming to changing your life completely like
6:23:25
make sure to focus your utmost attention to this problem and uh try to solve it as many times as possible because it has
6:23:31
been asked in so many companies. So that tells you something.
6:23:36
Okay. Now for the optimal solution we can actually observe something pretty interesting in this uh given left max
6:23:43
and right max that we have calculated the no if we notice in the given input
6:23:49
this is the biggest bar of height that is possible and we know that at any
6:23:54
moment at any location if you want to find the height the equation is this one that the minimum of whatever the left
6:24:01
max and right max we have minus whatever the height at current position we have
6:24:07
this is the equation to find that how much amount of water we can trap at any given unit or any given uh elevation.
6:24:14
Now the thing is if we notice in these two values left max and right max we are
6:24:20
actually finding something pretty interesting and the interesting thing we are finding is that the tallest part
6:24:26
that we have it actually divides the given input in two parts and it divides
6:24:32
how that if we observe the left most left max portion the left max portion is
6:24:38
always less than whatever the right max portion is
6:24:43
up until this point up until this point number seven. uh because notice all of
6:24:50
these values in all of these values the value of left max is actually less than
6:24:56
whatever the value of right max is and over here it's equal to right max
6:25:01
because of this particular uh tallest bar that divides two arrays and all on
6:25:08
on on the right side actually the R max is less than uh left max
6:25:16
and we can see those things over here that over here these are all the values
6:25:22
that are smaller than whatever the left max there is because for these four
6:25:27
values actually this particular the tallest bar actually becomes the left m
6:25:32
left max element and using this we can actually use it to our advantage because
6:25:38
remember at any moment if you want to find that what is the amount of rain water we can pound we only need to find
6:25:43
the minimum value of amongst this left max and right max Which means that this
6:25:49
tallest bar can actually be used in our help and we don't even need to calculate
6:25:54
the this whole left max and right max array by itself. We can actually use a
6:25:59
very beautiful concept that is present inside the given uh array traversal problems and that is two pointer
6:26:06
solution over here. In the now in the two pointer function we are going to have two v two variables left and right
6:26:13
initially located at first and last position and at every single time we are going to check that whatever current
6:26:20
element we have. So whatever height at element left or pointer uh left and
6:26:26
whatever the height at pointer r we are going to compare these two. So suppose uh the height at left pointer is
6:26:32
actually less than right pointer. What we are going to do is first we'll check that whether the current left pointer we
6:26:38
are at does it contains the left max height and we are going to initialize the left max variable to zero at the
6:26:46
beginning and at any point we are going to check that whether we need to update the value of left max. So at for left
6:26:53
max we are going to check two things. Uh we are going to we are only going to
6:26:58
check one thing. And we are going to check that whether the left max should be the maximum value out of whatever the
6:27:04
left max we have stored and whatever the height of left we are at. Uh so this
6:27:10
will always make sure that we have the most updated left max value. Once that is done we only need to use one equation
6:27:16
in this scenario and that equation is left maxus whatever the height we are currently at
6:27:24
uh of pointer L. If this is greater than zero, we can actually add it to our
6:27:30
total. So we can just say that total is whatever value we already had for total
6:27:36
plus we can add this whole function to it. And uh once that is done we will need to
6:27:43
update our left pointer. So on the left side we will move towards the right pointer and we will do left plus+. And
6:27:51
again suppose at any point we find out a scenario where the height at right is actually so height at right is actually
6:27:59
less than height at left. If that is the case we are going to repeat the same process. Uh let me use a different color
6:28:06
but this time we rather than doing it for left max we are actually going to do for the right max. So again we are going
6:28:12
to check for right max that what is the maximum amount we can find. So we are going to take maximum of whatever the
6:28:18
right max we already have and whatever the current right height we are at. Uh
6:28:23
and once that is done again we are going to use the same equation but rather than using left max we are going to use right
6:28:30
max minus whatever the height we are currently at uh for this r pointer and
6:28:37
uh if this is greater than zero we are simply going to add that value to our total variable whatever we calculate for
6:28:45
this one and uh once that is done our to our right variable is actually going to
6:28:50
move towards left side and we are able to achieve Leave this because there exist some bar that actually divides the
6:28:58
array in two portion. Because over here up until this bar always left max is
6:29:04
going to be minimum value and over here always right max is going to be minimum
6:29:10
value. And at any single position whenever we are at at any left and right
6:29:16
we always check their heights. Which means that suppose we reach this right
6:29:23
before still in the left side we will have to calculate all of these values before we get here and once we get to a
6:29:30
point where left is actually greater than or equal to right then we can simply break out of the loop and whatever value we have stored in the
6:29:36
total we can simply return that. This is a very beautiful approach and notice that we don't even have to use the full
6:29:42
equation over here. We are only comparing any one variable at any point in time a left max and right max and
6:29:50
every single time we are keeping track of whatever the left maximum or right maximum value that we have we have been
6:29:57
able to find. So if we if we use this approach if we use two pointer approach
6:30:02
and if we calculate the time and space complexity basically the time complexity for this one is actually going to be big
6:30:08
of n. So that is same as it is because uh in any case we are going to traverse over the entire input array. Uh but
6:30:15
thing is we are only doing it once. We are not doing it more than that. And if we see the space complexity actually we
6:30:20
are only storing couple of additional parameters uh like right max left max and we are storing two pointers left
6:30:27
pointer and right pointer. So we are not doing any additional data structure or
6:30:32
we are not storing anything else which means that our uh space complexity is actually going to be we go of one
6:30:38
constant time. So this is really amazing solution uh compared to all the other
6:30:44
approaches. This is the most optimal approach.
6:30:50
So first of all we are going to initialize our two variable left and right. Left is going to be zero. uh
6:30:56
right is going to be a height length minus one.
6:31:07
We are also going to initialize a variable total that is going to be total amount of water that can be stored and
6:31:12
we are going to initialize it to zero. We are also going to have two variables left max and right max and left max
6:31:19
would be the first element in whatever the height we are given. So height of zero and uh right max is going to be the
6:31:27
height of last element. So we can say height of right pointer.
6:31:33
And now we are going to run our loop. So while left is less than right.
6:31:41
First we are going to check for the height difference and whichever side has the lower height we are going to work on that side.
6:31:49
If left pointer has lesser height, we are going to work on the left side. So we are first of all going to see that do
6:31:54
we need to update the left max. We are going to check that whether we
6:32:00
are at any value where we can store some value. So we are going to check that if
6:32:06
uh left max minus whatever the height we are currently at on the left pointer if
6:32:12
that is greater than zero then we know that we are at a value and we can store some water over here. Uh so we will
6:32:18
update the total amount of rain water that can be harvested to total plus
6:32:25
whatever the height difference we have found over here. Which means that left max minus whatever the height we have
6:32:33
found over here. And uh once that is done, we need to update our left pointer to move towards
6:32:39
the right side. And if that is not the case which means that we need to repeat
6:32:45
the same process but now on the right side. So first we'll try to see if we need to update the value of right max
6:33:03
if we don't need. And now again we are going to check that are we at the valley on the right side
6:33:10
where we can store some rain water.
6:33:23
If this is greater than zero then we can update the total rainwater
6:33:44
and once that is done we will need to update the right pointer to move towards left direction. Okay I think that is it.
6:33:51
Once this while loop ends our to the total variable should have all the u
6:33:57
entire result and we can simply return that and this should give the total amount of rain water we can harvest.
6:34:04
Let's try to run this code.
6:34:09
Okay, seems we made some small mistakes.
6:34:21
Seems like our solution is working. Let's try to submit the code. And you can see that our solution works
6:34:27
pretty fast compared to a lot of other solutions. That is because we are using the most optimal approach. Uh I'm also
6:34:33
going to post this solution in the comments. Also I have created the solution where we need to use two
6:34:40
separate arrays to store the left mo left max variable and right max variable at every single any single position. And
6:34:47
uh you can check it out that solution as well from the comments
6:34:57
for this one the lead code problem number 26. If we see some of the popular companies who have asked this question,
6:35:03
there are companies like Apple, Facebook, Amazon, Microsoft, Google, Bloomberg, LinkedIn and Intel. They have
6:35:09
all asked this question. So that is why this is a really important question and let me let's just quickly go through
6:35:16
that what is the problem statement and then we would try to make the solution. Now in this case if you want you can
6:35:22
again read this whole thing. I'm just going to explain it to you quickly. Uh the problem we are given is that we are
6:35:28
given a sorted array. That is cool. Always love when the array is sorted. Makes things life so much easier. Now in
6:35:35
this case we are told that it could be possible that sorted array can have duplicated entries. So the moment we
6:35:42
identify duplicated entries we don't care about all the duplicated entries. But the thing we care about is that in
6:35:49
the initial portion of the array the all the distinct values has to be present.
6:35:54
All the other values we can mark them as anything like x or underscore or hash or whatever you want. We don't care about
6:36:00
those values. So in this case we are given an input array with seven characters. But if we see the number of
6:36:07
distinct characters we have we only have zero as a distinct character. Then we have 1 2 and 3. So 0 1 2 and 3. These
6:36:14
are the only distinct characters we have. Now for these three characters we don't care anything. So we are not going
6:36:20
to mark them. Basically they were duplicate entries and we are not concerned but in this case we are
6:36:26
concerned with the distinct characters and the moment we find the distinct characters we need to put them at the
6:36:31
beginning and then return uh whatever the solution we have been able to find. So what is the brute force way to do
6:36:38
this problem? Again brute force way is pretty simple. We just take uh one one value and we will try to see that okay
6:36:45
how many duplicates there is there is only and then we add that then keep on repeating the same process and then if
6:36:53
this is a duplicated entry again we move on to the next value. So this approach is guaranteed to give you the answer and
6:36:58
we go of n square solution. So brute force is always not a good way to go. The next way to go is that we can
6:37:05
actually try to do something smarter here. And what we are going to do is obviously you know this is a two-pointer
6:37:11
solution. So of course we are going to use two pointers. But since we are using here two pointers we are also going to
6:37:17
find a way to store the index value. So we are going to have a index value and
6:37:22
we are going to initialize it with starting position one. Now this first value is guaranteed to be a distinct
6:37:29
value because we are told that there is at least one value in the array and that value has to be part of the original
6:37:37
distinct value. So we are going to directly put it over here and that is why we put the index pointer at value
6:37:44
number one. Now index pointer is just a way for us to iterate over and also these two pointers what we are going to
6:37:50
do is initially they are both going to be they are both going to be located at the same place but the end pointer is
6:37:59
going to move a few steps ahead till it finds a distinct new distinct value that
6:38:05
is what we what it is going to do. So in this case currently uh starting and
6:38:10
ending pointer so this value is same as this one. So we need to skip this part. So we are not going to care about this
6:38:16
value. We are going to move the move to the next value. Now our starting and ending values both are located at this
6:38:22
position. This is a distinct value. The moment we find a distinct value since
6:38:27
uh we find the first distinct value for this index position number one. We are
6:38:33
going to add it over here. So we add value over here. The moment we add the value to our uh array and we find like a
6:38:42
new distinct value we are going to do index ++. So now our index value is
6:38:47
going to be two. And the next distinct character we find we are going to add it to position number two which we find
6:38:53
immediately. Immediately we find it because this is a new one because the end pointer went there and it didn't
6:38:59
find any any duplicator values. So again two comes over here and our index value
6:39:05
gets updated to value number three. Now we uh currently the scenario is that our
6:39:12
starting and ending values both are at the same position. So currently the starting pointer is located over here.
6:39:19
Ending pointer is located over here. Now this ending pointer is going to go one step further. So currently ending
6:39:25
pointer is at value number two. Again this value number two is the same as the
6:39:31
previous value. Since it is the same value, starting pointer is going to remain here. Ending pointer was here. It
6:39:38
didn't find anything. So now ending pointer we go will go to the next value. Next value is a distinct value. Again
6:39:43
distinct value starting and ending pointer becomes at the same position. Index value becomes four and the value
6:39:50
we add it to our input. So we added value number three to our answer. Now
6:39:56
again at position number three ending pointer go to the next. This is already uh three. Now ending pointer tries to go
6:40:04
to the next array ended. So we can't do anything about it. And this we can
6:40:09
return it as the answer. We don't care about these values because that is none of our concern. But you see even in this
6:40:15
case rather than coming on one side starting and ending pointers were working in
6:40:22
tandem to go from one step to the other step to find the answer. This was an
6:40:28
easy problem and in this case I intentionally chose this problem because
6:40:33
we are at the same apart from using two pointer solution at the same time we are use also using sliding window technique
6:40:40
because we are creating a window between starting and ending pointer and the moment we find some solution reasonable
6:40:46
solution we shift our window depending on the conditions and this is a
6:40:52
beautiful way to solve this problem and that is why I decided to keep this solution at the last. So let's see the
6:40:59
coding solution for remove duplicates from sorted array problem. Basically as mentioned we are going to initialize a
6:41:04
variable called insert index and this is going to mark at value number one because we already have the first value
6:41:10
stored inside our given input array because that is unique for sure. Then we start our for loop from the first
6:41:16
position not from the zero position because we already took care of the first value. And then all we need to do is we need to keep on in incrementing
6:41:24
this value number one I until we find the duplicate entries. And if the
6:41:29
entries are not duplicate which means we found the distinct value then at that time we are going to add that position
6:41:35
of nums of i to our insert index and which is located. Initially it would be
6:41:40
one and at the same time we would increase its value and then we would keep on repeating this process till we
6:41:46
reach to the end of the loop and basically in the end we simply need to return the insert index value and this
6:41:51
is going to be the whole solution. This is going to give us thath how many number of uh distinct elements are
6:41:57
present inside the given array. And uh let's try to run this code. Okay, seems like our solution is working. Let's
6:42:04
submit this code. And our code runs 100% nearly 100% faster than all the other
6:42:09
solution which is pretty good. If you want, I'm going to post the solution of this code in the comments of this video.
6:42:15
Also, at the same time, you can check out my GitHub where I have solution for every single video I have done so far.
6:42:21
and uh there are a lot of lead code problems. So this could be a good resource. I'm going to post this link in the description as well. Thank you.
6:42:34
Hello friends, we got a job at Microsoft but the thing is we are not going to stop lead coding because I like making these videos. Uh the video we are going
6:42:41
to do today is next permutation and if we see some of the popular companies uh who have asked this question there are
6:42:46
companies like Facebook, Amazon, Google, Apple, Microsoft, Bloomberg, Bite Dance, Uber, Goldman Sachs, Door Dash, Tik Tok
6:42:54
and Snapchat. So that's why I'm paying my utmost attention to make this video. I hope you also find this entertaining.
6:43:02
So this is a lead code medium problem and also a very well-like problem on lead code. If we just want to understand the problem statement, the problem
6:43:08
statement is only consist of one line that we are given an integer array called nums and we need to find the next
6:43:14
permutation for this nums array. Now the question comes uh which is very obvious that what does this next permutation is
6:43:20
being defined as. Well, one thing to find out is that you can actually try to read this whole definition and try to
6:43:26
understand that what does it mean or you can check out the example I'm trying to show you. uh suppose we are given
6:43:32
integer array uh that is like the value 1 2 3 right so this currently there are
6:43:38
three separate values the thing is let's try to consider and let's try to create like a lexographical value out of these
6:43:44
three so we will we can create a value that is like 123 now if we want to
6:43:50
create like a sorted ascending uh thing using these three elements like obviously uh the next sorted element is
6:43:57
going to be like 132 why because Okay, this value is 123. Using these three
6:44:03
characters, what is the next value we can make that is in the ascending order? Uh, we can make value 132. Now, if we
6:44:10
want to make the next ascending value, the value we would make, we would be able to make is going to be 213. The
6:44:16
next value is going to be 231. The next value is going to be 312. Value after
6:44:22
that is going to be 321. And after that, we won't be able to make any values. Now
6:44:27
if you look closely amongst these values all the values are sorted in ascending order. Uh for every single value we are
6:44:34
only picking the value that is going to be in its right right place. So for 123
6:44:40
we are not going to put like 213 after 123 because this value is going to be
6:44:45
smaller than this one. So that's why we are putting this 132 first. uh same way
6:44:50
this 231 is also at the correct place compared to this 213 and 312. So that is
6:44:57
the main logic behind it. Uh so suppose in the question if we are given the value that is like 123 then in that case
6:45:05
the next permutation has to be 132. But the thing is we don't need to return 132
6:45:10
as the answer. We need to return answer as like 1 3 and 2. So I think this explanation makes a little bit of sense.
6:45:17
Let's try to see some examples to try to understand that what does this problem is actually asking us to find. So in
6:45:22
this case okay currently we are given the nums array with the values 1 5 and 6. So again lexico graphically we will
6:45:28
be able to make value 1 5 and six right. So logically what should be the next value in line. So next value has to be
6:45:36
165 because any value after that would be would definitely be greater than this
6:45:42
one. So this is going to be the next permutation. Again same way if we are given the value 651. Now this is a
6:45:48
tricky case. Why? Because uh if we try to do like permutation of this 651 so
6:45:54
originally the whole permutation is going to look like this. So this is going to be the whole permutation. So if
6:46:00
the initial value is like 156 this these are going to be the subsequent values. So this value 651 is representing this
6:46:07
value 651 over here. Now if we see there is actually no next permutation in this case. So if that is the case basically
6:46:13
we will have to return the smallest possible value and the smallest possible value in this case is going to be 156.
6:46:19
So basically we are going to return 56 as the answer in this case. Uh again if
6:46:25
we take another number okay so this is like four characters long. So in this four character long number the next
6:46:30
permutation is going to be. So I know this is a very complicated question to understand but the thing is once you get
6:46:37
a grasp of how the permutations are being made you can simply know that what is the answer going to be. Uh so let's
6:46:43
see that what are going to be different approaches to solve this problem. Okay. So the first approach we are going
6:46:49
to try is going to be the brute force approach. Suppose this is the input we are given. So in the brute force approach what we are going to do is
6:46:55
depending on the input first of all we will try to make the smallest value possible. The smallest value possible in
6:47:00
this case is going to be values 1 2 3 and four. Okay. Now after making the smallest value possible, we are going to
6:47:07
try to explore every single values we can make inside the ascending sorted array. So the values we are going to get
6:47:13
is so just based on the few values we were able to make like these uh permutations
6:47:20
and eventually we came to the value that exactly matches this value and basically the next permutation out of this uh is
6:47:28
going to be the answer we need to return. So in this case we are going to return this as the answer 2143. The
6:47:33
question is okay this approach gave us the correct answer. But the thing is is this the right way to do it and answer is definitely no. Why? Because even for
6:47:41
a small example of four characters, we ended up exploring lot of possibilities. Like if you try to calculate the time
6:47:48
complexity in this case, the time complexity is going to be disastrous. It's going to be big of n factorial.
6:47:54
That is like the worst imaginable time complexity. So we have to find a way to do something better.
6:48:01
So before we come up with the optimal solution, we are going to take these four cases. We are going to see that what is going to be the next permutation
6:48:07
for every single one of them. And depending on the answer I would be able to show you that what is the pattern
6:48:12
that we are able we have been able to establish and using that pattern we would be able to create our optimal
6:48:18
solution. Uh so first let's start with this most initial case. In this case all the values are actually ascending order
6:48:26
increasing order. Uh which means that this is currently the smallest possible value we can make out of the values 1 2
6:48:32
3 4 5. Now the next permutation in this case is going to be where this five shifts on this left side and this four
6:48:37
shifts on the right side. Uh so basically the answer we are going to get is this is going to be the next
6:48:43
permutation for this value. Uh notice that currently we had value 45 and we
6:48:48
flip it to 54. We kept these values the same way they were because they were not
6:48:54
needed to be changed right now. Uh if we take this example, this is the exact opposite of this one. Why? because uh
6:49:01
this is the maximum possible value we can make in this case. If we want to see the next permutation basically there is
6:49:08
no next permutation which means we will have to go back to the very first value. So this is going to be the answer using
6:49:14
these two answers we are not able to establish much of a pattern over here but thing is now let's try to see some
6:49:20
middle cases. So in this case if we see we are given value like 25 431. So
6:49:26
lexographically we have been able to make a value like 25,431. Now in this case for the next
6:49:32
permutation we can either like try to see that okay what is going to be the value but I'm showing you a different
6:49:38
logic here and the logic I'm trying to establish is that typically we always follow from the left hand side uh to the
6:49:45
right hand side uh until the point we see continuous increasing elements. uh
6:49:51
again I'm talking about how to find next permutation and for that we will have to observe the current case that we have
6:49:57
been given. So over here so far 1 3 4 5 uh they are all currently in increasing
6:50:03
order which means that they are at the correct locations. Uh the thing is the moment we reach to this value number two
6:50:10
2 is actually smaller than five which means that the increasing order that we have been building up so far is no
6:50:16
longer true. So because this increasing order is no longer true, we will have to do something with this with this value
6:50:22
number two. Now we need to put it in some place where we are going to put it. The logic I'm suggesting is that we okay
6:50:30
now we have this value number two. We know that we will have to put it somewhere over here. Now where we are
6:50:36
going to put it? We are trying to find the next permutation which means the immediate next value that is greater
6:50:42
than this value uh that we can make. So logically what we are going to do is we
6:50:47
are going to scan all of these values. We are going to see that okay what is the minimum value from this two that we
6:50:54
have. So currently there is only one value that is less than two and that is this value number one. Now for this
6:51:00
value number one we are not going to do anything with this value number one. But the thing is the very next value that is
6:51:07
of before value number one has to be the most immediate greater value that is
6:51:14
compared to this two amongst uh the remaining portion. Again let me clean this up a bit and explain you again
6:51:20
because this is the most important uh topic. We check amongst these portion that okay what is the minimum first
6:51:27
minimum value we can find out that is less than this value number two. So that is value number one. What that means is
6:51:33
uh we already know that all of these values they are ascending in increasing order which means that the very next
6:51:39
value has to be the value that is greater than two but less than all the
6:51:45
other elements before that again if you don't understand just rewind it and see it again what I'm trying to establish.
6:51:52
uh so basically we found the value that is immediately greater than two but less
6:51:59
than uh this uh remaining values. So what we are going to do is we are going to swap these two values. Uh if we swap
6:52:06
these two values the answer we are going to get is and this is the answer we are going to get. The thing is uh you you
6:52:13
would must be saying that hey this is not the correct next permutation. I know this is not the correct next permutation
6:52:19
but what this is is that we actually found the first element that needs to be on the right place in order to generate
6:52:26
the next permutation and for all the remaining values we simply need to reverse them in the other way around. So
6:52:33
if we reverse them we will get a value that is 3 1 2 4 5 and this is going to
6:52:40
be the next permutation answer for this original uh input that we were given. So
6:52:46
basically we can just ignore these this case right now and thing is this is going to be the next very next
6:52:52
permutation. Now again let's go back on the logic that how we were able to generate this value. Well, uh definitely
6:52:59
we notice that all of these values 5 4 3 2 5 4 3 and 1 they have already been at
6:53:05
the correct place which means we have exhausted all the possibilities for these values where we can make some
6:53:10
adjustments and create like a greater value but that still remains smaller than the next value that means we will
6:53:17
have to do something with this element. So we will have to replace replace this element with some other element and the
6:53:23
only way to replace that is to find the value that is immediately greater than this two because remember apart from two
6:53:30
if we try to add four over here then that won't work. Why? Because there is still going to be a permutation that we
6:53:35
miss and that is the answer. Uh let's try to do the same logic over here again. So in this case if we try to see
6:53:42
uh currently this 3 4 and five they are increasing order right but we find this value number two. Now two is immediately
6:53:49
decreasing value compared to this remaining three values. Uh so sorry compared to its previous value which
6:53:56
means we will sum we will have to find some way to replace this two and make the changes amongst these values to
6:54:01
generate the next permutation. Uh how we are going to do it is that okay we will have to find a value that is greater
6:54:08
than uh two but uh there is still exist some value less than it. The question is
6:54:14
all the all these values they are all greater than two. So we are trying to find the immediate greater of two. So
6:54:21
which means we will have toh swap the values and you guessed it correctly between this two and three and that is
6:54:27
exactly what we are going to do. So if we swap that we are going to get an answer that looks like this. Now in this
6:54:33
case again this is not the correct but the thing is these two portions they became at the correct position and for
6:54:39
the remaining part we will have to just reverse that. So if we reverse that the answer we'll get is that would be the
6:54:46
immediate next permutation for this answer. So logic we are applying is that
6:54:51
basically we scan through the any given number. So in this case suppose this is the number we are given. What we are
6:54:57
going to do is we are going to jump through all the values till we find a value where the current value is
6:55:04
actually less than its previous value. So in this case that value we can find is four which means we will have to
6:55:09
replace four. So these three places they are already in the correct place. We don't have to do anything with them. Now for this four what we are going to do is
6:55:16
we are going to see that what is the immediate greater value of the four. So one way to do it is to find like the
6:55:22
lesser value than four. So lesser value than four is two. So one value before that is going to be the immediate
6:55:28
greater value compared to four that is five. So we will get a value that looks like this. And after that all the
6:55:35
values. So currently now these four elements are in the correct place. All the other values we will have to do a
6:55:41
reverse. This is the answer we need to return. In my personal opinion, this is a very hard
6:55:46
question because without major hints, you won't be able to solve it in an actual interview if you haven't seen it.
6:55:52
But thing is we are planning for a fang. So basically we will have to be vigilant and we have to make sure that we are
6:55:59
able to crack these kind of questions. Uh let's calculate the time and space complexity in this case. The time complexity is actually going to be bigo
6:56:05
of n because we only have to iterate over the given array like couple of times. This is space complexity. Apart
6:56:11
from using couple of variables, we won't have to use any extra space. So we can also complete this in like in place in
6:56:17
constant space uh complexity.
6:56:23
We implement the next permutation method. We are actually going to uh initialize couple of helper methods. So
6:56:28
first helper method we are going to create is going to be a swap method where if we are given any two elements
6:56:34
and we are given the given input array we would be able to basically swap their values. So depending on the index values
6:56:41
we would be able to make this that adjustment. Now the second helper method we are
6:56:46
going to create is going to be the uh reverse method. Now for this reverse method we are going
6:56:53
to again give uh the given array as the input and we are also going to give the
6:56:58
i value as like the starting index from where we need to start doing the reverse
6:57:03
operation. We are also going to create a j value as sort of like an end value uh and that is going to be the length of
6:57:09
given array. Now all we have to do is just run a while loop that while I is less than J.
6:57:18
Basically we are just going to call the swap method. And uh for the swap method we are going to provide the values of
6:57:25
nums uh J and I. And after that we are going to increase the value of I and we
6:57:32
are going to decrease the value of J. And this basically concludes our two
6:57:37
methods that we have been trying to create. Now uh let's go on the main method. So from the main method first of
6:57:45
all we are going to we will have to run a loop from the reverse end to find the
6:57:50
first value where the increasing order does not match. So we are going to initialize a variable called I and we
6:57:56
are going to assign it to the value of nums.length minus2. Why we are doing it nums.length length minus 2 because we do
6:58:04
not want to be in the out of bounds because we will always be we will always be comparing two i values at the same
6:58:10
time. Now let's initialize our while loop that while i is greater than or equal to zero uh and
6:58:17
the number of current i + 1 is actually less than or equal to the numbers of i.
6:58:24
So we are comparing two adjacent values each time. uh while this is true first of all we are going to uh decrease the
6:58:30
value of i. So the moment this loop ends basically we would be at the correct place where the i value is actually not
6:58:38
the correct value and needs to be swapped. So then we are going to check that okay if the given value of i if
6:58:45
that is greater than or equal to zero if that is the case which means we will have to do our swap operation uh and we
6:58:51
haven't found like the greatest value possible. So if that is the case, we are going to initialize a J variable and we
6:58:58
are going to assign it to like nums.length minus one again.
6:59:06
Okay. Again we are going to run a while loop that while we will have to find that whether the J value if that is less
6:59:14
than or equal to uh I. If that is the case, we will keep on decreasing the value of J. So eventually we would be at
6:59:20
a point where we are at the immediate value of J that is greater than I.
6:59:27
This is the case. Basically we are going to do like our swap operation and uh we are going to swap the values of I and J.
6:59:34
After swapping the operation we will have to do the reverse operation for the remaining values. So we are going to do
6:59:40
the we are going to call the reverse method and we are going to provide the value of the given array and we are also
6:59:46
going to do I + 1 because from I + 1 we will have to reverse all the characters and uh basically that's it. Uh this
6:59:54
should be able to provide us the next permutation. Uh let's try to run this code.
7:00:02
Okay, seems like our solution is working as expected. Let's submit this code. and our code runs pretty fast compared
7:00:08
to lot of other solutions and uh that's why this is like a really good solution but it's a really tough solution to
7:00:14
achieve. I will be posting this in the comments so you can check it out from there. Thank you.
7:00:31
So now we are going to understand the full topic of strings. we will understand that what is the core idea
7:00:38
about uh what strings is and what are the different kinds of questions can be asked. Now string is a very versatile
7:00:46
topic. So I have decided to break it down across uh multiple different
7:00:51
sections of the topics we are going to be seeing. So we would see some string topics in dynamic programming. We would
7:00:58
see some string topics and some other uh problems. But overall, this is for you
7:01:03
to give you the basic idea about what string is and what are the different questions. But this is not where the
7:01:10
topic ends. This is just where it starts and it is going to carry on throughout our remainder of the course. Strings are
7:01:18
one of the most unique and most versatile kind of a data structure that we can call. And the funny thing is if
7:01:25
you see the broader categorization of all the different data structures, you would not find string in any one of
7:01:32
these particular patterns. String is actually unique in a nature because it is the combination of all the characters
7:01:39
put together and that forms any particular string because characters on their own are pretty mundane because you
7:01:46
cannot do much of the task. For most of the things that we usually do in the real world, we need to deal with
7:01:53
different words, different characters, different serial ID, different numbers, different phone numbers, all sorts of
7:01:59
bunch of different items. And for that we use character as the underlying implementation. But only character using
7:02:07
is not going to be sufficient. And for that we need to use a way to store the combination of different characters. And
7:02:14
that's where the majority of string application comes into place. Strings
7:02:19
are defined in all the different popular languages. They have vast amount of uses
7:02:25
like you can use string for word processing, for HTML, for artificial intelligence, machine learning, data
7:02:31
storage, uh storing the encryption, certificates, storing the first name and last name of person. So all sorts of
7:02:38
things can be done using different kind different forms of strings. But the thing is in terms of the perspective for
7:02:45
DSA problems and DSA algorithms, we need to understand that how to perform
7:02:50
different operations on strings. What are the different ways we can do it and
7:02:56
what are going to be the common scenarios because remember you are always going to encounter where you are
7:03:02
using string as programmatically or in your interviews or in real world application. So now let's talk about
7:03:08
some of the basic operations that we usually follow and that we are going to learn more about in all sorts of 15 lead
7:03:15
code problems. So one of the most common things that you can do with the string is the creation and uh destruction of
7:03:22
the string. So if you want to create a string basically how it works is that in
7:03:27
the memory of the computer we are given a continuous block of memory is provided
7:03:33
where you can store any particular characters. Now these characters can have multiple meanings. You can store
7:03:39
simple values like a toz characters. You can store some se special characters like percentage, plus minus these kinds
7:03:46
of operator signs. You can also treat numbers as different characters as well and many times they are also being
7:03:52
stored inside the string or it could be combination of every single one of those. And that's why you have the these
7:03:59
strings that contains all of this jumbled information in a particular format that computer can understand and
7:04:05
humans can read. And then we will have to do multiple different operations. So first operation that where we are
7:04:11
creating a string can be typically done in big of end time because we don't know how many number of characters are going
7:04:17
to be there and initially we just start with one character and if we need more space we will assign two characters. If
7:04:23
we need more space, we will copy all the contains into four characters and so on and so forth. This is going to be the
7:04:29
most basic type of implementation. But lucky for us, most of the problems are
7:04:35
not required for us to do that and they are typically handled by the language of our choice. Be it Python, Java, Net, C#,
7:04:42
whatever it can be. Next thing is because strings are the combination of
7:04:48
multiple different characters. So we need some way for us to identify or
7:04:53
fetch each of the character. So fetching individual characters can be done in big of one time. Let me give you an example.
7:05:00
Let's say I create a string and I put down the value as path. Now I say that
7:05:06
what is the character present on the first index position or the second position inside this given string. Then
7:05:13
it can immediately return value a in constant time because this is a continuous block of memory. So it is
7:05:20
very fast for us to store or retrive values from any particular cell. Next
7:05:25
common operation that you can see is the length of the string. And once again the length of the string can also be done in
7:05:31
big go of uh one time. Now next operation is concatenation. Concatenation means that if we are given
7:05:37
string 1 s_ub_1 and string s_ub_2 then if we are combining these two strings to
7:05:42
create a new string s let's say s3 that is going to be combination of s_ub_1 plus s_ub_2 in some form. Then this
7:05:49
process is called concatenation and this can be done in bigo of m + n time where
7:05:56
m is going to be the length of s_sub_1 and n is going to be the length of s_ub_2. Same way opposite of
7:06:02
concatenation is substring and in order to create a substring basically let's
7:06:08
say if we are given a string that contains 10 different entries or five different entries and we only want to
7:06:14
want a certain portion of this size. So this process is called creating a substring out of the given original
7:06:20
string and this can be done in bigo of k time where k is the total length of uh
7:06:26
the any substring that you are trying to create. Same way we can split an existing substring and this splitting is
7:06:33
typically done in bigo of end time because overall the total number of characters remains the same. Finding any
7:06:39
particular character can be also done in big of end time as well because we need to iterate over every single value in
7:06:45
order to make sure that whether that character exists or not. So these are some of the common operations that we
7:06:51
usually do with strings. There are some more advanced operations as well that is pattern matching and understanding or
7:06:58
finding the meaning from any particular given string and there are a lot of different algorithms. Hello friends, hope you are having a fantastic day
7:07:04
today. So in this session we are going to do one of the easiest and most common problems in technical interviews. Uh
7:07:10
this is the fsbuzz problem that we all have heard of in the first year of computer engineering. And funny enough
7:07:17
this question has actually been asked in companies like Google, Apple, Amazon, Microsoft and Tik Tok. So without any
7:07:24
delay let's get started. And you can see that this has been a very well-liked problem and also lead
7:07:30
code easy problem. Basically we are simply given an integer n and for this integer n we need to return a string
7:07:37
array uh called answer and we are being told to return one index array. These are just all of these things to make it
7:07:43
slightly more complicated but this is a very easy problem. So what we need to do is we need to iterate over until this n
7:07:50
values and for every single value we need to check that if that value is divisible by 3 and five we need to
7:07:56
return phase bus. If it is only divi divisible by three, we need to return fizz. And if it is only divi divisible
7:08:02
by five, we need to return buzz. And if none of these cases apply, then we need
7:08:07
to return the value as it is. But instead of integer, we need to return the value as string inside the string
7:08:13
array. So let's try to understand this with couple of examples. Let's say that if we are given number input n is equal
7:08:19
to 5. In this case, we will need to iterate over values from 1 2 3 4 and 5.
7:08:26
And for each one of them we will have to create a string array. So let's create let's assume that this is our array. Now
7:08:31
this value number one is not divisible by three or five. So in this case we are going to return one as the string value
7:08:38
as it is. Same way two is also not divisible. So we are simply going to return two as it is. Now at value number
7:08:44
three if the value is divisible by three and not divisible by five. This is the condition met over here. In this case we
7:08:50
can check we need to return fizz as the answer. So over here we are going to answer fizz because this value is only
7:08:57
divisible by three. Same way four is not divisible by three or five. So we can just simply return four as it is. And
7:09:03
for the value number five since it is only divisible by value number five we need to return buzz as the answer. And
7:09:10
this is what we need to return. All we need to do is we simply need to create a for loop for the given n value. And then
7:09:17
we need to iterate over every single value. And we need to create the conditions in such a manner that if the
7:09:22
value is divisible by three and five in this case we need to return we need to add phase buzz for the uh new list we
7:09:30
have created. If that is not the case once again we can have an else if condition and again if the value is
7:09:36
divisible by three then in this case we need to add fizz. If it is else if if it
7:09:42
is divisible by five then we need to return or add the word buzz into our array list. And if none of the case is
7:09:49
there then whatever the value of i is we need to add that value of i into our array list or array. Uh and that's it.
7:09:56
So this is the whole solution. If we see the time and space complexity time complexity is simply going to be big of
7:10:02
n where n is the number of inputs that we are given and space complexity is we
7:10:08
you can debate this with your interviewer because we are being asked to return a new list. If we consider that an extra space then it would be big
7:10:15
of n. But if it if that is not the case then in order to run this code we don't need any extra space. So we can just
7:10:21
complete this whole solution in go of one time. So for the problem first of all we are initializing a new array list
7:10:26
called result where we are going to store all the values. Then as mentioned we are iterating over every single value
7:10:32
inside the given input and we are the starting value is one because we are being told that this is a one index
7:10:37
array. Just a small tweak. then we are having bunch of our conditions and uh first condition is if the number is
7:10:43
divisible by three and five we need to add word fsb bus if that is not the case and else if it is only divisible by
7:10:49
three then we add word num fizz if it is only divisible by five we add word bus
7:10:54
if none of the case is there then we simply add the value as it is but we add the string value of i and then in the
7:11:01
end we simply return the result so let's try to run this code and as expected our
7:11:06
code runs successfully let's submit this Okay. And our code runs pretty fast compared
7:11:12
to all of the other solutions and also pretty efficient in terms of space complexity. But I don't even think that
7:11:17
this matters that much. This is a really easy problem.
7:11:23
Now, as promised, let me show you some of the important resources that you can use in order to prepare better for your
7:11:29
upcoming technical interviews. I have actually created some resources. I have also stored all the code that I'm doing
7:11:35
in a GitHub repository and also some of the important YouTube channels that you should always check out if you want to
7:11:42
gain much more insight into how IT technology works, what are the new things happening in the IT industry and
7:11:48
any of the thing that you want to learn. So without any delay, let's get started. So the number one thing I want to show
7:11:54
you is this document that I have created where I have posted uh some of the full courses that I have created on various
7:12:01
topics like data structure algorithms. Uh funny thing is I have actually solved the entire blind 75 and I have already
7:12:08
put it in a single video. So I have mentioned that over here and also some of the other important items that you
7:12:13
should learn if you want to prepare better for your technical interviews. Next we have this list of 125 or I think
7:12:21
100 130 questions. Uh amongst these questions I have sorted these questions
7:12:26
based on the difficulty plus based on the topic. For most of the videos uh
7:12:31
most of the problems I have created video solutions. So if you are not able to find it, you can go to the video solution also. These questions are
7:12:38
actually lead code links for any particular question. And the important part is that I have actually divided it
7:12:45
by the number of times it has been asked by different companies. Now I know that not everyone wants to get a job at fang
7:12:51
company or some other company. But needless to say if you are preparing for a tech interview, this would be very
7:12:57
much helpful because it would give you an idea that how popular that particular question is, what at what frequency it
7:13:03
has been asked and if you are directly preparing for those specific companies. Say for an example if we see this problem race car. So this problem has
7:13:10
been asked it by 92 times at Google which means if you are preparing for Google you should understand that these
7:13:17
are the type of questions that you are going to encounter. So it can be really helpful with your prep that you are prep
7:13:22
journey that you are doing. So this is the list of all the questions. Next I have also portrayed down the experience
7:13:29
of all the technical interviews or all the major interviews I I have had in my career. uh and I have also provided that
7:13:36
which uh are the interviews I got selected which which are the ones I got rejected and actually I got rejected at
7:13:42
hundreds of companies but I haven't put all of them I just put like some of the popular ones where I had some good
7:13:48
experience and then we have this GitHub repository so if we go to this GitHub repo uh it contains lot of important
7:13:56
information about all the problems that I have solved so far on the lead code so many times I can understand that on the
7:14:02
lead code if you need the information you might need to have like a paid version and readily the items may not be
7:14:08
available. So for most of the popular questions you can actually go here and you should be able to find appropriate
7:14:14
solution for that. So this would be really helpful uh to a lot of people. Now the important resource that I was
7:14:21
talking about if you are preparing for your tech career or your interviews or
7:14:26
your journey I would really encourage you to go and check out this channel freecodecamp.org. Now for sure they
7:14:32
don't need any introduction from my side like as you can see that they have like millions of subscribers and also
7:14:37
thousands of videos on their channel but good thing about this is that all the videos are actually full-fledged
7:14:43
courses. So if you are interested to learn any new technology they probably have a course for that. Funny thing is I
7:14:50
actually created and uploaded couple of courses on this channel as well. So first one is master behavioral
7:14:55
interviews and uh second one is I think it should be popping up soon and yeah second one is master technical
7:15:01
interviews. I'm also in preparation to create more courses for this channel because I personally feel that this is
7:15:06
much more advantageous and it reaches to lot of broad uh broader people and uh
7:15:12
this is like few of the resources and let me know in the comments if you want to see more resources related to
7:15:18
different type of stuff like maybe technical system design concepts and system design interviews. So I can also
7:15:23
share that in the upcoming videos as well.
7:15:32
Hello friends, hope you are having a fantastic day today. So in this video we are going to solve a very popular lead code problem that has been asked in tons
7:15:39
of companies. So without any delay, let's get started. So the lead code problem we are going to solve is called
7:15:44
longest common prefix and you can see that this is a lead code easy problem and also a very well-liked problem on
7:15:50
lead code. Now the problem statement is very simple. We simply need to write a function to find the longest common
7:15:56
prefix of string amongst an array of strings that we are given as the input.
7:16:01
And if we cannot find any prefix, we need to return an empty string. So let's try to understand this with couple of
7:16:07
examples. So in this case, what is the common prefix that we are able to find that is common for all the four strings
7:16:13
that that is currently given. The answer is quite simple. L is the common entity or common prefix that we can find. So in
7:16:21
this case we will return L as the answer. Now let's take another example. So in this case what should be the
7:16:27
answer? Well first it seems like this RA A is going to be the answer but RA is
7:16:33
not present in this string. So in this case since we cannot find any common prefix so we need to return an empty
7:16:39
string as the answer. Now to solve this problem we are going to use a very simple logic. input we are given we are
7:16:46
going to treat as if the string one that is currently present this is the longest
7:16:52
longest prefix that can be possible because any other values they have to
7:16:57
have all the characters that are present in the string one how can it happen let's assume that in the example
7:17:03
currently the substring one is the value like xy z something like this now even
7:17:08
if all the other values like xy z a b c something like that and then xy z and
7:17:13
then all the long values still the longest common prefix has to be the
7:17:19
first substring as its whole. So it cannot it can never be longer than the
7:17:24
first string inside the given array that is a given fact. So using this logic we will try to treat that what if the first
7:17:32
string is the longest common substring and by treating this we will try to
7:17:37
compare this string with all the remaining strings that are currently present inside the array and that's how
7:17:43
we will be able to reach to the solution so let's try to understand the approach that I'm suggesting suppose this is the
7:17:48
input we are given so now based on our approach we will try to see that let's
7:17:54
assume that this is the longest current prefix that we So we create a variable and we are going
7:18:00
to store that as if the prefix currently is going to be the whole first string because we just prove that it cannot be
7:18:07
longer than this one. And now we will try to compare this string with the
7:18:13
remaining all the other remaining strings to see that till what point we
7:18:18
are true or we are correct. So first we will compare it with the word flower. So
7:18:24
if we see that whether the flow is part of the flower, we only need to compare the first four characters if they are
7:18:30
equal to each other. We can simply say that this is still the longest common substring which is the case in this case
7:18:36
because this flow is part of this flower. So so far the longest prefix we
7:18:41
have found is going to be the first string in itself. Now we will repeat the
7:18:46
same process once again. Now we will try to compare flow with float. Now flow is
7:18:54
not part of the substring float. So what we can do is we will try to get rid of
7:18:59
the last character because we are trying to check for the prefix. We are now only going to check for the first three
7:19:05
prefix. So now we will compare flow with float. And we can see that this flow is
7:19:11
actually a prefix of this float. Which means so far the longest prefix that we have been able to find is fl. Now we
7:19:18
also get rid of this one. And now we will move on to the next value. So once again we are comparing flow with flight.
7:19:26
Now currently flow is not a substring of flight which means we will once again get rid of one character and try to
7:19:32
check if L is the part of the substring. Currently L is actually part of the substring. So in the answer we found and
7:19:39
since there are no more strings left we compared every single string and we found out that L is the common substring
7:19:47
amongst all four strings and that's why we are going to return L as the answer. Now let's assume that for some reason uh
7:19:54
this last character does is something random. Let's say that this last character is uh ABC. Now once again what
7:20:02
we will do is at this step uh once again now with this L is our prefix that we
7:20:09
have been able to find and we are going to compare this with ABC. Now since we cannot find L as part of this ABC. So
7:20:16
once again we will get rid of L and we will only compare F. F is also not a prefix of this ABC. So in this case
7:20:23
since we cannot find any value in the inside the prefix. So we will simply return an empty string. So this is the
7:20:29
simplest logic to solve this problem. And if we see time and space complexity in this case, the time complexity is
7:20:36
actually going to be the sum of all the strings we go of s. So every single
7:20:41
character inside the string would be uh the total worst case scenario time complexity which is pretty reasonable
7:20:48
because these are very quick operations and this is still like big of n time complexity. If we consider n to be the
7:20:54
total number of characters and space complexity is actually going to be bigo of one because apart from using like few
7:21:00
variables we are not using any extra space. So which is wonderful. Now let's see the coding solution for this one. So
7:21:06
now first of all we are going to check for the edge case that if the given string is equal to null or strings.length is equal to zero that
7:21:12
then we can simply return as an empty string. If that is not the case, we are going to mark the very first element
7:21:19
inside the strings array as our by default prefix and then we will start comparing prefix with all the other
7:21:26
remaining strings inside the given array. So we have notice that in our for loop that we are iterating over the
7:21:31
strings array. We are actually starting with I is equal to 1 because I is equal to0 has already been taken care of. And
7:21:37
then after iterating over it. Now we are simply going to check for every single string compared to our prefix. So we are
7:21:45
only going to check that whether this given prefix is actually an index of the given string. If that is not not the
7:21:53
case, if that is not equal to zero, which means we will have to subtract one character from our given prefix. uh and
7:22:00
once again recheck this possibility. So we will keep on iterating this process and if uh at any given moment we
7:22:07
identify that the given prefix is empty because continuously we are subtracting one character. If that is the case we
7:22:13
can simply return as the empty string. If that is not the case and we get out
7:22:18
of the loop then we can simply return whatever the value we find inside the prefix uh variable. So this is it. Now
7:22:25
let's try to run the code. Okay, seems like our solution is working
7:22:31
as expected. Let's submit this code
7:22:36
and our code runs 100% faster than all the other solutions. Also, it is excellent in terms of space complexity
7:22:42
as well. And once again, I'm going to be submitting this inside our GitHub repository. So this is the GitHub
7:22:48
repository that I'm talking about where I have solved hundreds of lead code problems and all of these are some of
7:22:54
the most popular uh lead code problems that has been asked at bunch of different companies hundreds of times.
7:23:00
So if you are if you feel that you are stuck with any of the lead code problem I would highly encourage you to come over here and check for the solution.
7:23:07
Also I have created this document on Google drive where the in this document
7:23:12
first I'm providing all the full courses that I have completed so far. But the most important point for this document
7:23:19
is actually this list of all the 130 questions. If you see these questions
7:23:24
are divided based on the topics the difficulty level and also how many times
7:23:29
they have been asked by separate companies. So this is very important information for any single one of you
7:23:36
who is currently just trying to improve on the data structure algorithm related lead code problems or actually preparing
7:23:41
for different interviews because I know times are tough companies are laying off people left and right so it never hurts
7:23:48
to be interview ready and always be on your best game.
7:23:59
Hello friends, we are not employed by a fing company. So let's not stop lead coding till we get there. Today we are going to do encode and decode strings
7:24:05
lead code problem. And as you can see this is actually a lead code premium problem. If we see some of the companies who have already asked this question
7:24:11
where I want to get a job there are companies like Facebook, LinkedIn, Google, Square, Uber, Microsoft and Apple. So all of my favorite companies
7:24:18
have asked this question. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
7:24:24
So this is a lead code medium problem and basically we are given a list of strings. Now we need to design an
7:24:30
algorithm where we are actually encoding this given list of strings into a single string. Then we are told that that
7:24:36
single string is supposed to be sent over a network and then when we get back to the second machine we need to decode
7:24:43
that given string into the original list of strings. So let's try to understand this with an example. So suppose we are
7:24:49
given a string s where we are given bunch of different strings that looks like this. So after this we will
7:24:55
actually create an encoded string. Now this encoded string is combination of all of these four items and it is just a
7:25:02
single string. So let's say that this is the encoded string we have created. Now uh after creating this encoded string,
7:25:08
we need to write a function to decode the string as well. And after we decode the string, we should get a response
7:25:14
that exactly looks like this. And this would be the original decoded string we would get. And this is what we need to
7:25:20
return. So we need to return the algorithm to encode the string and also an algorithm to decode the string. So
7:25:25
let's see that what would be the different approaches we can take. Okay, suppose this is the original string we
7:25:30
are given and we need to encode the string and decode the string. The idea is we are actually going to use an extra character and where we are going to use
7:25:36
an extra character we would put it where one string ends before other string starts and we will keep on repeating the
7:25:43
same process and all we have to do is so that would be the way to encode the string. After encoding the string when
7:25:48
we have to decode we will just simply take that character and the moment we reach that particular character we would
7:25:54
know that okay this is the place where one string ends so we would create a new string for that and then we will repeat the same process. So let's see that in
7:26:00
action. So first of all suppose we take this character that looks like this hash right I'm just taking any random
7:26:05
character. Uh the idea is you can discuss with your interviewer that what kind of character you can take. So
7:26:11
suppose I take this hash. Uh now I do encoding string. So the encoded string is going to be a b. Then the moment I
7:26:18
identify that the strings ends over here. I would put a hash and I would keep a continuous string. Now I realize
7:26:24
that okay this is a new string b. So I would add a value b. Again I would put a hash. Now again this value is c. Again I
7:26:30
would put a hash and again at the end I would find this value a b c and that would be the end of the string. So now I
7:26:37
have created an encoded string. Now if I want to decode the string uh the decoding would work like this. So first
7:26:43
of all I'm iterating until I find that this is a valid string. So valid string is AB. Now I realize that okay this is
7:26:49
the hash and hash is the character that I put it as an extra character as an encoding mechanism. So I would remove
7:26:55
this hash and I would treat this as a single string. Now I would again start creating a new string. So again I find
7:27:02
this value B. The moment I encounter the string hash, I would treat this B to be a separate string. Again I would
7:27:08
encounter this value C. And again I would encounter this value ABC. And this is the way we will we are going to
7:27:14
encode and decode the string. And this solution would work as expected. If we see the time complexity in this case,
7:27:20
the time complexity is actually going to be big of n. Why? Because we will have to iterate over all the characters that
7:27:26
are present inside this given string s to first of all encode and then decode. So overall it would be 2 n. But we can
7:27:32
generically write it to be big of n. Now if we see the space complexity in this case the space complexity is actually
7:27:37
not that much because we anyways we will have to create an encoded string and decoded string and all we are doing is
7:27:42
just using an extra space to solve this problem. So this is pretty simple uh to
7:27:48
me. Okay, suppose this is the string we are
7:27:54
given and the idea is we are actually going to add four bits that are going to store the length of any given uh sub
7:28:00
substring and then we are going to keep on repeating the same process and we are going to create the encoded string. So
7:28:05
let me quickly show you what I'm suggesting. First of all, we would have an encoded string where first four
7:28:11
character is actually going to store the information that what is the next length of substring that is coming that we are
7:28:16
going to iterate over. So in this case this is actually length three. So if we add it in binary it's represent as 0 1
7:28:22
1. So we are actually going to have 0 0 1 1 to be the length and then we are
7:28:27
going to store these three characters as a b c. Okay. Now we are done with that again. Now this ends the first
7:28:34
substring. So now this is of length two. So length two becomes 0 1 0. Now we are
7:28:40
going to do the same thing. And then we are going to store this value a. And now
7:28:45
this is also of length two. So again we will repeat the same process and we are going to store the value of x and y and
7:28:52
this is the encoded string. What we have done basically is we have actually created block of four bits that keeps
7:28:58
the information that okay in the next subsequent value these are the three characters that you will have to iterate
7:29:04
over and that is uh how we are going to decode it. So let's see the decoded string in action. In the decoded string
7:29:11
first of all we are going to iterate over this given encoded string. Now we iterate over these four characters and
7:29:16
we find that okay value is actually three which means that next three characters are the characters of one of
7:29:21
the substrings that we will have to separate. So we will iterate over these three and put it in a substring and we will get a substring like a b c. Again
7:29:28
we will iterate over these four characters and we realize that the value is actually two. So because two we will
7:29:34
have to iterate over these two elements and we would get the value a b. Now again we would iterate over this next
7:29:39
four bits and we find that value is actually three uh two again. So we will iterate over two more characters and we
7:29:44
will get the value xy and then we would have a decoded string. So this is also another way to store uh all the values.
7:29:51
Now this solution also works as expected but I don't think that anyone is able to come up with this in the interview. So I
7:29:58
just showed you this approach just for the explanation purposes but actually I'm going to in the coding I'm going to
7:30:03
show you the first approach that I solved earlier.
7:30:10
So first of all we are going to do the encode function. So let's take care of some edge cases first.
7:30:17
If that is not the case we are actually going to take a random variable that is not part of this uh original given
7:30:23
string. So we are given the condition that there could be 256 characters uh inside the asky character for this given
7:30:30
string I. So what we are going to do is we are going to take the 257th character as the character that is a separator
7:30:36
between any two strings. So first of all let's just create a string uh called separate
7:30:44
and we are going to assign the character 257 to it. Now we will start building
7:30:50
our string. Now we will iterate over this given list of strings. So first of all we are going
7:30:56
to append the value of whatever the string we are iterating over and the
7:31:03
moment the string ends we are going to add the separate character. Once this loop ends basically we should have done
7:31:09
with encoding our string. Now all we have to do is just delete the last character uh because that would be an
7:31:15
additional room and once that is done all we have to do is just simply return this given this new string builder we
7:31:22
have created. So now we are done with encoding our string. Let's decode our string. If this given string s is
7:31:28
actually of size uh whatever the located at 258 which means we are dealing with an empty string list. So in that case we
7:31:35
will simply return a new error list and we should be done. If that is not the case which means that
7:31:40
we have a separated string. So uh let's just assign a new character. All we have
7:31:45
to do is just return an array list where we are going to uh separate based on this given uh separate character.
7:31:53
And that's it. Let's try to run this code. Okay, seems like our solution is working
7:32:00
as expected. Let's submit this code. And our solution is actually pretty fast
7:32:05
compared to lot of other solution. It's not most optimal because I did not choose the approach two. And uh let me
7:32:11
know if you want to see the code for approach two as well. Thank you.
7:32:22
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do palendroic substrings lead
7:32:29
code problem. And if we see some of the companies where I want to get a job who have already asked this question, there are companies like Facebook, Amazon,
7:32:35
Twitter, Google, Microsoft, Uber, Goldman Sachs, Apple, Bloomberg and LinkedIn. So that's why I'm paying my
7:32:41
utmost attention. I hope you also enjoy the video. So this is a lead code medium problem
7:32:47
and basically we are given a string s and we need to return the number of palendroic substrings that exist inside
7:32:52
this given string s. Uh lucky for us we are given the definition that what a palendrome is. Basically a palendrome is
7:32:58
a string that reads the same from backwards and frontwards. So suppose we are given a string like this GG. If we
7:33:05
read it from the backwards or frontwards in both the cases the answer remains the same. Also one more example A B A this
7:33:11
is also an example of palendrome because in either case we read it the answer remains the same. Now a quick question
7:33:17
for you guys that whether this character B is this an example of a palendrome or not and the answer is yes this is also a
7:33:24
palendrome. Why? Because if we read it from the left and also read it from the right we get the same result. But if we
7:33:30
are given a string that looks like this AB this is not a palendrome because if we read it from the left and from the
7:33:35
right the answer is not the same. So these are some of the examples of a palendrome. Um we are also given the
7:33:41
definition of a substring but I don't think that it is necessary to define it is actually pretty trivial. Now let's
7:33:46
try to understand this problem with an example. Suppose we are given a string S that looks like the C A B A. Now in this
7:33:52
case we need to find that what are the number of palendroic substrings that exist. So we can clearly see that we
7:33:57
have a palendroic substring that are these four characters are actually palendrome in itself because as I
7:34:03
mentioned earlier over here that even a single character is also a palendrome in itself. So we already have four
7:34:09
palendroic substrings so far. But if we notice over here we also have one more palendrome that is this aba and that is
7:34:15
also a palendroic substrings which means that in this case we need to return five as our answer that we can actually make
7:34:22
five palendroic substrings for this given string s and this is what we need to return. So let's see that what would
7:34:27
be the different approaches to solve this problem. Suppose this is the s we are given and
7:34:33
we need to find that what would be the brute force solution for this problem. Well, we have to understand that we need to find all the existing palendromic
7:34:39
substrings that are present inside this given string s which means we need to find the substrings. So what we can do
7:34:44
is we will make all the possible substrings that we can make from this given s and then we will check that whether that substring is a palendrome
7:34:51
or not and simply we will get our desired answer. So if we see that in action for this particular string we can
7:34:56
actually make substrings that looks like these.
7:35:02
So these are all the substrings that we can make from this given string s. Now all we have to do is check that whether
7:35:07
any given string is a palendrome or not. And in this case we will find that these four strings are palendromes and also
7:35:13
this string is a palendrome. All the other strings are not palendromes. And then in the end we can return five as the answer for this problem and that
7:35:19
would be a valid answer for this problem. But what is the issue with the brute force approach? Well the issue with the brute force approach is that
7:35:25
the time complexity in this case is actually going to be big of n cq. Why n cube? because it takes n square time
7:35:31
just to make these substrings and then it takes n time to check whether a substring is a palendrome or not. So
7:35:36
cumulatively this is a very bad time complexity and we will have to find a better approach.
7:35:42
So before we move for the optimal solution first of all we'll have to build some intuition behind it that how to identify a palendrome. Well in the
7:35:48
palendrome there could be two possibilities. The palendrome could be of odd length or it could be of even length. First let's see that what would
7:35:54
be the scenario in the odd length. So suppose we are given this character O. This is a palendrome in itself. We have
7:36:00
already ident identified that because if we read it from left or right, we get the same result. Right? Now, if I decide
7:36:05
to add two more characters x o xx at the edges, this still remains the
7:36:10
palendrome. Which means that because both of these x's were same uh and this middle p middle value was a palendrome
7:36:17
in itself, this whole thing actually became a palendrome. Again, if I take it even further, if I add two more
7:36:22
characters BB again, this whole thing still remains a palendrome. And if I keep on adding same values as long as
7:36:29
they are same this will always remain the palendrome. But the moment I add a value that likes a and b now this whole
7:36:36
thing is not a palendrome because these two values are different but this portion is still a palendrome and also
7:36:42
the smaller portions still remains the palendrome which means we can define that the palendromes are like an onion
7:36:48
where the middle value remains the same and because of the middle values all the other subsequent values where the values
7:36:54
are actually same uh the palendroic property is sustained why I'm giving so much explanation for that uh is you will
7:37:01
see it In the optimal solution and the o in the odd cases we only have one value as the middle character but inside the
7:37:08
even character suppose we are given a value like BB. So this is a palendrome in itself and both values are same
7:37:14
because both values are same uh this is an even length and this is an even length par palendrome. Now again I
7:37:20
decide to add two more characters xx because they both are same this still remains the palendrome. Again I add
7:37:26
value a a this is also a palendrome but the moment I add a value that is different like x and y now this whole
7:37:32
thing is not a palendrome but this middle portion still remains a palendrome. So that is the important
7:37:37
property that in case of odd length we we have a middle character of the palendrome that is a single character
7:37:44
and all the other characters has the same value. In case of the even length palendrome we have two characters that
7:37:50
are same. So that is important two characters they are both same and then all the other characters they are also
7:37:55
same as well and a smaller palendrome is forming a larger palendrome and let's see that how can we use this property to
7:38:02
find an optimal solution. So suppose this is the example we are given and we need to find the optimal solution for
7:38:08
that. The idea is that at any given character, we are actually going to see that whether could this be a middle of
7:38:13
any palendrome and if it is the middle of the palendrome, we are going to keep on expanding our palendroic search and
7:38:19
we are going to keep adding our answer result. First of all, let's see for this character number C that can the C be
7:38:25
part of any middle of the palend palendroic substring or not. Well, we already know that the C is a substring
7:38:30
in itself because if we read it from left or right, we get the same result and we are also going to have a variable called answer. So, initial value was
7:38:37
zero. Now because this C so now because the C is a palendrome in itself we are going to add the value to our answer as
7:38:43
well. Now we are going to see that whether the C is a middle of the palendrome or not which is not why because if we see the left of the string
7:38:49
and right of the uh C this is actually a null value and this is A which means both are not same. So because both are
7:38:54
not same this is not part of any middle of the substring. Now we are going to have this value A. Again we are going to
7:39:00
repeat the same process. Well A is a palendrome in itself. Uh so we are going to add the value to our answer first of
7:39:06
all. So this becomes two. Now again we are going to check that whether this a is a middle of any palendrome or not. We
7:39:12
also have to check for both the cases that could this be of oddlength palendrome or an even length palendrome.
7:39:17
So for oddlength palendrome like the both left and right value would be same and for even length palendrome the value
7:39:23
would be same with that itself. So first of all we are going to check with this a. So the left value c and right value
7:39:30
is actually b. So both are not same. also they are not same of this A and B which means this is not an oddlength
7:39:36
palendrome and even length palendrome. So we are good to go. Now we will move on to the next value B. Now this next
7:39:42
value B is a palendrome in itself. So we will update the value inside our answer to three. After doing that we are going
7:39:48
to check that could this be the middle of any palendrome or not. So we will check the left and right value. Left value is A and right value is also A. So
7:39:55
because these two are same we can define that this B is actually part of the middle of the palendrum which is of odd
7:40:01
length and we are going to keep on expanding our palendrome. So now this B A B so sorry now this A B A is also
7:40:09
palendrome. So we will update our answer immediately. So answer becomes four. Now now again we will keep on expanding our
7:40:15
palendrome. So if we do a left and right over here the left value is C and right value is actually null. So these two are
7:40:21
not same. Because these two are not same we no longer have a palendrome. So we will break out of the loop. Now again we
7:40:26
still have one more character left to check. So again we will check for this value number a. So a is a palendrome in
7:40:32
itself. We will put the answer as five. Then again we will check that whether this a is a is that a middle of any
7:40:37
palendroic string or not. So we check left and right value. Left value is b and right value is actually null which
7:40:43
means these two are not same and they're not same of this a as well. Uh so immediately we will break out of the
7:40:48
loop and we can return uh and the next value over here is actually null which means we don't have anything. we have
7:40:53
reached to the end of the string. So this is the answer we need to return in this case that five would be the answer
7:40:59
and we will return that. Let's see one more example S where we will find the even length uh palendrome. So over here
7:41:06
again we are going to repeat the same process. So first of all we'll take this character number C. Can this C be part
7:41:12
of the any middle of the substring or not? So this is not part of any middle of the substring and we will have an answer variable. So first of all we'll
7:41:18
initialize it to one because C is a substring in itself. Now we will move on to the next value A. So A where A if we
7:41:24
check the left and right pointer left is C and right is B. So these two are not same. So immediately A is also not the
7:41:29
middle of any new palendrome but it is a palendrome in itself. So again we will update the value to two. Now again we
7:41:35
are at this position number B. Now at this position number B if we compare left and right values. So left value is
7:41:41
A and right value is B. So these two are not same but these two are actually same. So we can define this BB to be a
7:41:48
middle of a palendrome. And this is the property we are going to use right. And by the way for this B first of all we'll
7:41:54
update the value to three. And now we have this BB that is a middle of the sub palendrome. Now immediately we will
7:42:01
check the left and right value. So left value is A right value is also A. Again these two are same. So this is also
7:42:06
palendrome. So we will update our answer again. So this becomes four. Now again we will check the left and right value
7:42:12
over here. So left value is C and right value is actually null. So in this case these two are not same. because these
7:42:17
two are not same. We will break out of the loop and we will say that okay so far we have found something decent. So uh right now again we are at this
7:42:24
position number B. Now remember that this becomes a little bit tricky that it
7:42:29
becomes easy for us to if we check over here this left value is actually B and right value is A. So again these two are
7:42:36
same but we should not fall for this trap because we have already concluded this BB to be a middle of the
7:42:41
palendrome. So we will not consider this one and this is also not a palendrome which means that the answer we will only
7:42:48
update by one and that this value by itself is a palendrome and at the end we
7:42:53
will check for this value number a and a is a palendrome in itself. So we will update the value to be six but in the
7:42:59
left and right there is nothing. So we won't do anything with that and in the end we will return this answer six to be
7:43:05
the final answer. And this is the solution we are going to use to find all the palendromic substrings inside any
7:43:10
given string s. This is the final optimal solution. If we see the time and space complexity in this case, the time
7:43:17
complexity is actually going to be big of n². Why n square? Because it takes us n time to iterate over all the values.
7:43:23
And for any single value, we might have to iterate over all the remaining values. So that takes n² time. But this
7:43:29
is still a big improvement compared to our brute force approach which had the uh n cube. If we see the space
7:43:35
complexity in this case, the space complexity is actually going to be big of n because at any given point we might
7:43:41
have to store all the values of n.
7:43:46
First of all, we are going to initialize a variable called answer and we are going to assign the value as zero. Now we are going to create a for loop and
7:43:52
iterate over the given input. Now we have two possibilities. Any single character inside this given
7:43:58
string s could be the middle value of any oddlength palindrum or an even length palindrum. So we are actually
7:44:04
going to make two calls to our check palindrome method where we are going to return a value that whether this given
7:44:09
string is a palendrome or not and we are going to add that value to our answer variable
7:44:16
and inside this method we are going to pass the value of our string s and we are also going to pass the character
7:44:21
position of the middle variable. So the oddlength palendrome would have the same
7:44:27
middle value. So we will pass on that and for even length we are going to pass two values. So over here we are we will
7:44:34
pass I and we will also pass I + 1 to be the middle characters. Basically after we get out of this loop we should have
7:44:40
our answer ready. So we can simply return that.
7:44:46
Now let's create this check palendrome method and we will initialize a variable called
7:44:51
count to count the number of palendromes we encounter. Now we are going to run a while loop that while the left and right
7:44:58
pointer are inbounds or and not out of bounds and while their character positions are same. So which means they
7:45:05
satisfied to be the parent room. If that is the case, we will keep on updating their values and we will keep on adding
7:45:10
our count variable and in the end we will return the count variable. So let me quickly type it type that.
7:45:18
So this condition defines that whether this given string is a valid palendrome or not. If that is the case, we will
7:45:23
decrement the value of our left pointer. We will increment the value of our right pointer
7:45:29
and we will increment the value of our count variable. And once that is done, once we get out
7:45:36
of this loop, we simply need to return the count variable and that's it. Uh so let's try to run
7:45:42
this code. Okay, seems like our solution is working as expected. Let's submit this code
7:45:50
and our code runs pretty efficiently and I will be posting this solution in the comments so you can check it out from there. Thank you.
7:46:03
Hello friends, we are not employed by a fang company. So let's not lead coding till we get there. Today we are going to do longest palendroic substring lead
7:46:10
code problem. And if we see some of the companies where I want to get a job who have already asked this question, there are companies like Amazon, Microsoft,
7:46:16
Google, Adobe, Apple, Bloomberg, Goldman Sachs, Tik Tok, Uber, Bite, Dance,
7:46:22
LinkedIn, Tesla and eBay. So that's why I am paying my utmost attention. I hope you also enjoy the video. This is a lead
7:46:29
code medium problem and also one of the very well-liked problems on lead code. uh basically we are given a string s and
7:46:35
we need to return the longest palindromic substring that is present inside this original given string s. So
7:46:41
in order to understand this problem first of all we'll have to identify that what is a palendroic string and a
7:46:46
palendroic string is basically as the name suggests any string that forms a palendrome and we know that palendrome
7:46:53
is any string where if you read it from left to right or right to left uh the number of sequencing is uh same. So in
7:47:00
this case AA is actually an example of a palentromic string. Also A B A is also
7:47:05
an example of palentroic string because in either of these two cases whatever you whatever side you decide to move
7:47:12
along the number of character occurrences remains the same. So that's why they are palendrome. And now our aim
7:47:18
is to find the longest palendroic substring inside this g given original string s. This is not a very good
7:47:25
example to understand. So let me create a custom example. In this case, we need to find that what
7:47:30
is the longest palendroic substring. So if we see this string S by itself, it's actually not a palendrome. But if we see
7:47:37
these three values A, B, A and we get rid of this B and D, we can actually create a palendrome. Which means in this
7:47:44
case, we can return the answer as a B A to be longest palendroic substring that
7:47:49
is present inside this given string S. And this is exactly what we need to return. So now let's see that what would
7:47:55
be the different approaches to solve this problem. In order to understand the brute force way we'll have to identify
7:48:01
that what is the thing we need. We need the longest pelandromic substring that is present inside this original given
7:48:06
string s. So the aim is that we need to find a substring. Uh so why don't we
7:48:11
just use the brute force method and we find every single possible substring that we can make out of this given
7:48:16
example s. So we can make bunch of different substrings. Let me just draw some substrings over here.
7:48:22
So these are some of the substrings that we are able to generate from this original given string. Now our aim is to
7:48:28
find that what is the palendroic substring. If the substring is palendroic, we will find its length and then we will try to find the longest
7:48:34
palendroic substring in that way. So we can clearly see that in this case this aba is going to be the answer for this
7:48:40
longest palendroic substring and eventually we would be able to find the solution using the brute force method.
7:48:46
But what is the issue with this? like issue is actually pretty evident that even for this four character string we
7:48:52
will we actually had to create bunch of different substrings and out of all of the those substrings we will have to
7:48:57
find some effort and resources to find that what is the longest pandomic substring. So that is just waste of time and uh energy. If we see the time
7:49:04
complexity in this case the time complexity is actually going to be big of n cq. Why m cq? because it takes n
7:49:09
square time just to create these substrings and after doing that we will also have to identify that whether those given strings are actually palendroic
7:49:16
substrings or not and which is the longest amongst all of them. So that also takes n time. So that's why the overall we can write it as we go of n
7:49:22
cube time complexity. So let's see that what would be the better approach to solve this problem.
7:49:29
Well before we come to the optimal solution first let's build some intuition behind achieving that optimal solution. Uh the idea is that we need to
7:49:36
find the longest palendroic substring. Now there are two possibilities. We could have an odd number of string that
7:49:42
is a palendrome or we could have an even number of string that is actually a palendrome. Now in each cases the middle
7:49:48
value is actually providing some interesting results. And the thing is that in both the cases the palendromes
7:49:54
are actually built around these middle values. How? Let me quickly show it to you. Well, if we just take this madam
7:50:00
for an example over here, we can actually conclude this d to be a substring in it. And because this is a
7:50:06
single character substring we can actually conclude this to be a palendrome as well. Uh because if we read from this left direction or right
7:50:13
direction in each cases we are going to get the same result. Now if we add these two a's uh to this d we will also get
7:50:20
the substring that looks like this a d a. Now in each cases this d remains
7:50:27
common but the left value and the right value because they both are same we can conclude conclude this string to be a
7:50:33
palendrome as well. Now again if we repeat the same process and we add this m and m again because they both are same
7:50:40
and we are adding at the corners. So if we add them we will get a value that looks like this. Now this d originally
7:50:48
was a palendrome. After adding this a a it remain palendrome because both
7:50:54
character had the same value and again after adding this mm again it the whole thing remained the palendrome because
7:51:00
they both had the same value. Now in this case if I extend and if I add a value that looks like X and Y over here.
7:51:06
So this X and Y is actually not same. So this whole thing will not be a palendrome but this middle portion will
7:51:13
actually be a palendrome. And in this case because we had odd number of characters that are forming a character.
7:51:19
We actually have just one value that we can consider as middle value and all the other values from this middle value are
7:51:26
actually just a bunch of set of characters. they who both have same same values. Let's take an example for this
7:51:33
even number case. Now in this case actually we have two middle values and the two middle values are BB. Now if we
7:51:39
were to consider this BB this is actually palendrome in itself because again by definition even if we go from
7:51:44
left or right in each cases we are reading the same value. Now again this a
7:51:50
a both are same value and they are actually same value that corners our original given middle values. So if we
7:51:57
form a value that looks like this, this BB was already a palendrome. And the two values we added, they are also same. So
7:52:04
because they are same, this whole thing actually becomes a palent room. And again just like this case, if we add an
7:52:10
X and Y over here, this whole thing will not be a palendrome. Only this A B A
7:52:16
would remain palendrome. So now after knowing this solution, actually it becomes really easy for us to identify
7:52:22
that what would be the optimal solution.
7:52:28
Suppose this is the example that we are given and we are trying to find the optimal solution for that. What we are going to do is we are actually going to
7:52:34
expand on the corners and we are trying to see that whether the left and right value of any middle value if they are
7:52:39
actually same or not. If they are same we can consider the whole part to be part of any palendrome. If they are not
7:52:45
same then we will move on to the next value and start doing the same process. Now there could be two possibilities. We
7:52:50
could have an oddlength palendrome where we will only have one middle value or we could have an even length palendrome
7:52:56
where we will actually have two middle values. So in each cases we will have to take care of them. So I'll be showing
7:53:02
you the odd example first and then I'll show you the even example and uh basically it's slightly different idea
7:53:09
and uh I'll just show you when we when we go there. So first of all we are going to take this value x. Now we are
7:53:16
going to expand upon the corners. uh so we are going to see that whether this x could be the middle of a longest
7:53:22
palentroic substring. If that is the case then we will expand upon this x. So we will try to see its left value and
7:53:29
right value. The left value is actually null and right value is actually m. Now uh this left and right they are not same
7:53:35
and also this middle value is actually not same with this right value and it's also not same with this left value which
7:53:41
means in each cases this x is actually not part of the middle of longest palendroic substring. So we will get rid
7:53:46
of it and we will move on to the next value. Now we are at this value number m. Again we try to see the what is the
7:53:52
left and right value. Left is actually x. Right is actually a. Again they both are not same and none of them are same
7:53:58
with this m. So which means that now we will move on to the next value. Next value is actually a. Again the left
7:54:04
value is m right value is d. Nothing is same. So we will move on to the next value because this is also not a part of
7:54:10
the pendrome. Now we are at this position number d. Now if we take the left and right value the left value is
7:54:15
actually a and the right value is also actually a. So because this left and right value is same this d could be a
7:54:21
middle of any palendrome. We don't know if it is the longest palendroic substring or not. Now the longest
7:54:26
palendroic substring that we have found so far is actually of length one. Why length one? Because any character in
7:54:32
itself is also a palendrome. Remember that. So that's why now we have this new substring that looks like this aba. This
7:54:39
is also palendrome and we will try to see that whether it is longer than whatever the existing palendrome we have
7:54:44
which is true that this aba is actually longer. So we'll have to update the value of this ab over here saying that
7:54:50
this is the longest palendrome we have found so far. We will keep on expanding on its corner. So so far the values we
7:54:57
have is a again we will move on the left and right pointer. So this is m and this
7:55:02
is also m. So because they both are same again we can consider this to be a palendrome and the previous longest
7:55:09
palendroic substring we had was aba but this is actually greater than that so we'll update its value and now the
7:55:16
longest palendroic substring we have found so far is madam m a d a m now again we will go and uh repeat the same
7:55:23
process repeat the same process over here we will have the value y and over here we will have the value x so these
7:55:29
two are not same so because these two are not same now we are no longer forming a pendro So we will have to get
7:55:34
out of it. So we will just move on to the next value. And if we move on to the next value, the next value is actually
7:55:40
a. So again this a left value is d and right value is m. So this is not a
7:55:46
palendrome. We will go back to m. m is also not part of any middle of any palendrome. And this y is also not part
7:55:52
of any middle of the palendrome. So now we are done for our example so far. And in this case whatever the answer we have
7:55:58
found over here for the longest pelenromic substring which is m a d a m we will return this as our answer and
7:56:04
this solution would work work as expected. Now this was the case of odd number of palendrome that be that is
7:56:10
being the longest. Let's see the even number of palendrome. So in this case again we are going to repeat the same
7:56:16
process. First of all we'll take this x we take the left and right value. Again we don't find any interesting so we'll
7:56:22
move on to the next value. Now next value is a. Again we check left and again we check right. uh we don't find
7:56:27
anything right uh because so we'll move on to the next value. Now again we are at this position number B. Now we are at
7:56:34
this position number V. If we check the left value we find A. But if we check the right value we actually find another
7:56:40
B. So because these two are same actually the combination of these two B's could be the middle of the longest
7:56:47
pelenroic substring and that that is going to be true in this case. So we are going to expand on a little bit
7:56:54
differently now. Now we are going to have this BB as the middle of the longest palendroic substring we have
7:57:00
found so far and we will repeat the same process. So we will try to find that whether what are the left and right
7:57:05
values. So left value is a and right value is also a. So again this is a b a
7:57:10
because these two are same and this middle portion we just consider it to be the middle. So this is also forming a
7:57:16
palendrome and the longest palendroic substring we had so far was only of length one and then when we found this
7:57:22
BB it become of length two and now we have this aba so this is of length four.
7:57:28
So because this is of length four, we will have to update the longest pelenomic substring we have found so far to be a ba. Now again we will repeat the
7:57:35
same process. So if we again go left and right this is actually x and this is y. So now these two are not same because
7:57:42
these two are not same. So now we will just get out of it. We will again check with this a and y we don't find any
7:57:47
parent and we would be done with this one. So in this case we would return this ab ba as part of our answer and
7:57:54
that would be the final solution. So the time complexity in this case is actually going to be bigo of n². Now why n
7:58:00
square? Because we will have to iterate over every single value to see that whether that is the middle of the longest paralomic substring or not. That
7:58:06
takes uh n time and if we will have to iterate over all the values on the left and right side to see that whether it's
7:58:12
the longest parendomic substring or not. Which means that in the worst case scenario we might have to iterate over n
7:58:18
square times to find the answer. uh in terms of space complexity we might have to keep track of big of n characters at
7:58:24
any given moment where n is the number of characters present inside the string. Now this is actually a much bigger improvement compared to our brute force
7:58:31
approach which had the time complexity of big of n cube actually. And now let's move on to the coding.
7:58:40
First of all we are going to check some edge cases. If that is not the case, we are going to
7:58:46
run a for loop across the given string. For the any value we are iterating over,
7:58:51
we don't know that whether it is the middle of the longest palendroic substring of an even length or of an add
7:58:57
odd length. So at any given time we are actually going to have two variables that call a function where we are going
7:59:03
to check that whether the odd length or even length palendroic substring can it
7:59:08
be the middle of any palendrome and uh so first I'll create two variables and we'll name it as len one and len two and
7:59:16
we are going to call a function called check palendrum inside this function we are going to provide the value of given
7:59:22
string s current position of i and we are considering this to be an odd length
7:59:27
so That's why we are considering I to be the middle element. Also, we are going to create a variable called length two.
7:59:34
We are again going to call the check palendrome function. We're providing the value of string s. We are also providing
7:59:41
the value of i and we are also providing the value of i + 1. Uh why + one? Because remember that in the even length
7:59:47
palendrome, we actually have two middle entries. And that is how we are going to do it. And also we are going to have a
7:59:53
variable called length where we are going to keep track of the maximum length of palendrome we have found so
7:59:59
far. Remember that amongst these len one and len 2 at any given moment if we identify
8:00:06
that there exists some valid palendrome and we have found the maximum value we might have to update the value of the
8:00:12
maximum variable. So we are going to check for that condition as well. For
8:00:17
that we actually need two pointers called left and right. And we are going to check that whether the given length
8:00:23
we are getting if that is greater than the left and right length we have already found so far. The thing is we
8:00:29
haven't declared these variables yet. So first of all let me quickly declare these variables and we are going to
8:00:34
initialize their values as zero. We are going to update the value of the
8:00:41
left pointer uh and that will be decided based on the value of I. So we are going
8:00:46
to do I minus whatever the value of uh current length we have found we need to
8:00:52
do it divide by two but thing is we don't know that whether that uh length is odd or even so we will subtract it by
8:00:59
one value and then we will divide it by two. So in any case we will get the correct result for the left pointer and
8:01:05
for the right pointer we are actually going to do I plus whatever the length
8:01:11
we have found uh divided by two and this should give us left and right pointer to
8:01:17
create the desired substring and after uh we we run out of the loop we will
8:01:23
simply return the substring. So now we are done with uh most of the
8:01:28
logic in the main uh method. Now we'll just have to create this check palindrome method.
8:01:35
So let's assign the value L and R uh for the ease of our use.
8:01:42
Now we are going to run a while loop that until the point when we have a valid balindrome we will keep on
8:01:48
reducing the value of left and updating the value of right and we will check that whether both values are same or
8:01:53
not. We'll also take care of some edge cases.
8:01:59
While the existing value is a valid palendrome, we will reduce the value of left pointer
8:02:05
and we'll update the value of right pointer. This while loop, we will return the
8:02:10
whatever the length we have found so far. This should do it. Let's try to run this code.
8:02:18
We will have to update the value of this right pointer by one. Let's try to run the code again.
8:02:25
Okay, seems like our solution is working. Let's submit the code. And our code works as expected.
8:02:32
I'll be posting this in the comments so you can check it out from there. Thank you.
8:02:44
So today we are actually going to solve very disliked and yet very popular lead
8:02:50
code problem that has been asked at tons of different companies. So let's get started with the question. So the lead
8:02:56
code problem we are going to solve is called text justification. Now you can see that this is a lead code hard
8:03:01
problem and also very controversial problem because it has more dislikes compared to likes. But the thing is the
8:03:08
only reason I'm solving this problem is because this has been asked at tons of different companies. So let's try to
8:03:13
understand the problem statement. Basically we are given an array of string called words and we are also
8:03:18
given a number called max width. Now we need to format the text such that each
8:03:24
line exactly has the max width character and is fully justified from left to
8:03:30
right. Now there are some conditions that we need to follow in order to complete this exercise. So we should
8:03:37
pack our words in the greedy approach that is pack as many words as you can in
8:03:42
each line and every single word or between two words we need to have at least one extra space when there is
8:03:49
necessary. Also we need to make sure that every single line exactly has the max width characters. Now we are also
8:03:56
being told that whenever we are dealing with extra space between the words they should be distributed as evenly as
8:04:01
possible. But in case we realize that the number of spaces on a line does not
8:04:06
divide evenly in that case we need to divide it between the words and if there
8:04:12
are empty slots on the left we are going to be assigning more space on the characters on the left hand side and the
8:04:18
last condition is that for the last line of text it should be left justified and there should not be any extra space
8:04:25
inserted in between the words and that's it. Now there are bunch of different
8:04:30
conditions. So let's try to understand this with some of the actual examples for this problem. Now we are given a
8:04:37
string or string of words such as like this where it says that this is an
8:04:43
example of text justification and we are being told that the maximum width in
8:04:48
every single line we can have is 16 characters including the spaces nothing more than that. So let's try to see that
8:04:54
how does the solution for this problem should look like. Now the thing is first let's see that how many characters this
8:05:01
this needs. This has four characters then this has two characters and then this also has two characters and this
8:05:07
example has seven characters. So let's try to sum up and we are trying to root for or find the greedy approach and
8:05:14
trying to find as many words as possible within the boundary of 16 characters plus we will have to consider at least
8:05:21
one space between any single two words. Which means what I'm suggesting is that
8:05:26
instead of treating this as like 4 3 and 2 by character size, we are actually going to add one more value to it. So
8:05:33
let's assume that this is five, then this is three, this is also three and this is eight. Okay. So now let's try to
8:05:38
do the sum and see how many characters can we fit in. So for this one we
8:05:44
maximum is 16. Now if we do sum of these three characters then it we get the
8:05:49
value as 11 and then 11 + 8 if we try to do it goes 19. So 19 actually exceeds
8:05:56
the value we are trying to find which means we cannot include this character example. Okay. So after realizing that
8:06:03
we are only going to be working with these first three words. So we have this first word that is this. Second word is
8:06:09
is and third word is n. Okay. And we need to put this in one line such that
8:06:14
the first word starts with t inside this given line. The last word has to be n
8:06:20
because we don't want to have extra space after the last character for this particular line. Okay. So this has to be
8:06:28
first word. This has to be last word and we need to have in total 16 characters.
8:06:34
Now the thing is originally we saw that we were considering five and then three and then three in terms of characters.
8:06:40
But now let's not consider these spaces. Let's only consider the values of the characters. Which means this is
8:06:47
currently four characters long. This is two characters long and this is also two characters long. Which means in total we
8:06:53
are working with 4 + 2 + 2. So total eight characters we already have. Which means we will have to add eight spaces
8:07:00
inside this first line that we are trying to create. Which means we can put four spaces over here. And we can put
8:07:07
four spaces over here because remember there should not be any space after this character n. So in this case we are
8:07:14
going to build a string like this. So first is going to be this then there are going to be four empty strings. Then
8:07:20
there is going to be character is and then once again there are going to be four empty strings and then we are going
8:07:26
to have the character n. And this is going to be the first part of the answer where we have created a string that
8:07:32
contains exactly 16 characters. And we will still have to iterate over these
8:07:37
remaining files. So let's try to do repeat the same process once again. So
8:07:43
let me just write down this answers at some place. Now let's try to find the second line. And let me also clean this
8:07:49
up a bit. Now let's repeat the same process for the remaining characters. So
8:07:54
how many number of characters this example has? It has seven but we also need to consider space. So there are
8:07:59
going to be eight characters. This off is going to have three characters. This text is going to have five characters
8:08:05
and this justification is going to have 14 characters and since this is the last
8:08:11
character we are not adding an extra space and remember there is also a dot
8:08:16
or the full stop behind this line that this is also considered as an extra character. So now let's try to do the
8:08:22
sum. So if we do 8 + 3 we get 11 11 + 5 we already get 16 which means we are by
8:08:29
default default at the 16 character mark which means we cannot add this justification. So now let's try to deal
8:08:36
with just these three words and once again we are dealing with example and then off and then text. But now we
8:08:44
are not going to include spaces for now because we will have to do that calculation. So now this is seven
8:08:49
characters, this is two characters and this is four characters. So if we do the sum we get the value 13 which means in
8:08:57
total maximum width we need 16 which means we still have three extra spaces that we have to distribute. But the
8:09:02
thing is now this is not an even number of spaces. This is odd number of spaces.
8:09:08
So we will have to divide if we try to divide this by two we get like 1.5. But this is we cannot divide 1.5 spaces. So
8:09:15
we are going to divide two spaces between here and then we are going to put one space here because remember
8:09:21
there has to be at least one space and also if we divide three by two we get like two options 2 + 1. So this is how
8:09:28
we are going to distribute the spaces. So second answer is going to look like this where it's going to be example then
8:09:34
we are going to have two spaces then we are going to have off then we are going to have one space and then we are going
8:09:39
to have text. So this is going to be the second line of the answer. So let let's also mark this one as well. Okay. And
8:09:46
now in the end we are only dealing with just single uh word or in the in the last line and this word contains 14
8:09:53
characters. So we are going to have it justified completely on the left side of the portion. So the answer is going to
8:09:59
be quite simple that we are simply going to create an answer with justification
8:10:04
and whatever is the remaining value or in order to make it 16 we are just going to add extra spaces and this is going to
8:10:10
be the answer. This is the total three strings that we will have to return and this is the whole explanation of the
8:10:16
problem. Now how to solve this problem? Well actually I was also solving this problem along with explaining the
8:10:23
problem because we don't have to use any extra specific data structures. We don't have to use any extra characters nothing
8:10:29
like that the simple logic is that we are simply going to run an algorithm. The purpose of this algorithm is that
8:10:36
let's assume that currently we are given the word string and this are given like x number of words okay and each of them
8:10:43
are in the different length and let's assume that the width we are given is for some example 10. Now the logic is
8:10:51
first we are going to keep on iterating across every single word plus adding a
8:10:56
space with each word until the point where we run out of the number 10. The
8:11:02
moment we run out of the number 10, we will have to identify that what was the last character that would not be
8:11:07
included or the last character that we can only include. So let's assume that we can only include up to this point uh
8:11:14
in just one line. Which means for the next line we can consider all the remaining items. Now amongst these lines
8:11:20
we are going to forget about this one space for now. We are only going to be concerned with the size of the characters and see that what is the size
8:11:28
of the characters we get. So let's assume that we get the size of the characters as six. So if the size of the
8:11:33
characters is six for each one of them which means we will have to deal with four extra spaces. So now in this case
8:11:39
if we are dealing with even number of extra spaces so we can simply put it between these two words or all the
8:11:45
remaining portions between any number of words and then we once again mark it as
8:11:51
the part of the answer. So these three X are going to be part of the answer. So x then two spaces once again x then two
8:11:57
spaces and then x uh and then we are going to repeat the same process for this remaining item. So this is the
8:12:03
whole solution and in order to build the string we need to use string builder class or some sort of that
8:12:09
functionality. Every single language has the way in order to build the string and
8:12:14
this problem seems hard but it is only hard because you will have to iterate over this logic and there are a lot of
8:12:21
different edge cases that we need to cover. What is the importance of this problem? Well, this is how actually the
8:12:27
tools such as like word and Google doc, they actually do the text indentation.
8:12:33
So that's why this problem is has practical implication. There are no questions in that. But this specific
8:12:39
problem does not deal with data structure as much as it deals with iterating over different strings and
8:12:44
trying to find the reasons. And that's why this is such a highly unliked problem on lead code. Um but it is what
8:12:51
it is. I just explained you that how to solve this problem. When we do see the coding solution, things will make much
8:12:56
more sense. If we see time complexity, it's pretty simple that the time complexity is going to be bigo of s
8:13:02
where s is the total number of characters that are present inside uh this word string. So, sum of every
8:13:08
single character. So, first of all, we are going to initialize an array list called lines to store our answer. Then
8:13:14
we are going to have an index value starting at zero. And we are going to have the condition that while index is less than the total words that
8:13:21
do.tlength. We are going to first of all do the count of all the words uh length of all the words. And then we are also
8:13:28
going to keep track that what was the last value of that we have been able to identify it and we are going to put it
8:13:35
as index + one. Then we are simply going to iterate over that while last is less
8:13:41
than the current words.length length. We are simply going to keep on adding the value and keep on checking that if the
8:13:47
next adding the next word exceeds the max width or not. If it exceeds the max
8:13:53
width, we simply break. If it does not exceed, we increase our counter and we also increase the last pointer as well.
8:14:00
Now once we are at this stage, we are at the position where we have the values of
8:14:05
the words that can be included in one single string or one single line for the answer. So we are going to initialize a
8:14:12
string builder. Now for this string builder we are going to append the words that are currently present at the index
8:14:18
and then we are simply going to check that if we are on the last line of the line and it has only just one word we
8:14:25
are going to do a left justify which means we are going to put all the words that are currently present and whatever
8:14:30
the difference is we are simply going to append that for the for our existing string builder. If that is not the case
8:14:38
uh then we are going to calculate that how many spaces do we need to do. So we are going to calculate the spaces based
8:14:44
on the maximum width minus the count divided by the difference of the number of words and then we are going to check
8:14:49
that what should be the extra spaces divided amongst each entity. So for that we are actually using the modulo
8:14:55
function by diff and then we are simply going to run a couple of for loops in order to generate the string that I just
8:15:02
explained and then in the end we are going to add all the strings that we have been able to create inside our
8:15:08
string builder and return lines that we have create initi initiated originally the array list as the answer. So let's
8:15:15
try to run this code.
8:15:22
Okay, seems like our solution is working as expected. Let's submit this code.
8:15:28
Our code runs 100% faster than all the other solutions, which is pretty awesome. And uh once again, I will be
8:15:34
posting the solution in the GitHub repository. Link is in the description. Thank you.
8:15:46
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do palendroic substrings lead
8:15:53
code problem and if we see some of the companies where I want to get a job who have already asked this question there are companies like Facebook, Amazon,
8:15:59
Twitter, Google, Microsoft, Uber, Goldman Sachs, Apple, Bloomberg and LinkedIn. So that's why I'm paying my
8:16:05
utmost attention. I hope you also enjoy the video. So this is a lead code medium problem
8:16:11
and basically we are given a string s and we need to return the number of palendroic substrings that exist inside
8:16:16
this given string s. Uh lucky for us we are given the definition that what a palendrome is. Basically a palendrum is
8:16:22
a string that reads the same from backwards and frontwards. So suppose we are given a string like this G g if we
8:16:28
read it from the backwards or frontwards in both the cases the answer remains the same. Also one more example A B A this
8:16:35
is also an example of palendrome because in either case we read it the answer remains the same. Now a quick question
8:16:41
for you guys that whether this character B is this an example of a palendrome or not and the answer is yes this is also a
8:16:48
palendrome. Why? Because if we read it from the left and also read it from the right we get the same result. But if we
8:16:54
are given a string that looks like this a b this is not a palendrome because if we read it from the left and from the
8:16:59
right the answer is not the same. So these are some of the examples of a palindrome. Um we are also given the
8:17:05
definition of a substring but I don't think that it is necessary to define it is actually pretty trivial. Now let's
8:17:10
try to understand this problem with an example. Suppose we are given a string S that looks like the C A B A. Now in this
8:17:16
case we need to find that what are the number of palendroic substrings that exist. So we can clearly see that we
8:17:21
have a palendroic substring that are these four characters are actually palendrome in itself because as I
8:17:27
mentioned earlier over here that even a single character is also a palendrome in itself. So we already have four
8:17:32
palendroic substrings so far. But if you notice over here we also have one more palendrome that is this aba and that is
8:17:39
also a palendroic substrings which means that in this case we need to return five as our answer that we can actually make
8:17:46
five palendroic substrings for this given string s and this is what we need to return. So let's see that what would
8:17:51
be the different approaches to solve this problem. Suppose this is the s we are given and
8:17:56
we need to find that what would be the brute force solution for this problem. Well, we have to understand that we need to find all the existing palendroic
8:18:03
substrings that are present inside this given string S. Which means we need to find the substrings. So what we can do
8:18:08
is we will make all the possible substrings that we can make from this given S and then we will check that whether that substring is a palendrome
8:18:14
or not and simply we will get our desired answer. So if we see that in action for this particular string we can
8:18:20
actually make substrings that looks like these.
8:18:26
So these are all the substrings that we can make from this given string S. Now all we have to do is check that whether
8:18:31
any given string is a palendrome or not. And in this case we will find that these four strings are palendromes and also
8:18:36
this string is a palendrome. All the other strings are not palendromes. And then in the end we can return five as the answer for this problem and that
8:18:43
would be a valid answer for this problem. But what is the issue with the brute force approach? Well the issue with the brute force approach is that
8:18:48
the time complexity in this case is actually going to be big of n cq. Why n cube? because it takes n² time just to
8:18:55
make these substrings and then it takes n time to check whether a substring is a palendrome or not. So cumulatively this
8:19:01
is a very bad time complexity and we will have to find a better approach. So before we move for the optimal
8:19:07
solution first of all we'll have to build some intuition behind it that how to identify a palendrome. Well in the palendrome there could be two
8:19:13
possibilities. The palendrome could be of odd length or it could be of even length. First let's see that what would be the scenario in the odd length. So
8:19:20
suppose we are given this character O. This is a palendrome in itself. We have already ident identified that because if
8:19:25
we read it from left or right, we get the same result. Right? Now if I decide to add two more characters x o xx at the
8:19:32
edges, this still remains the palendrome. Which means that because both of these x's were same uh and this
8:19:39
middle p middle value was a palendrome in itself, this whole thing actually became a palendrome. Again, if I take it
8:19:45
even further, if I add two more characters BB again, this whole thing still remains a palendrome. And if I
8:19:50
keep on adding same values as long as they are same this will always remain the palendrome. But the moment I add a
8:19:57
value that likes a and b now this whole thing is not a palendrome because these two values are different but this
8:20:04
portion is still a palendrome and also the smaller portions still remains the palendrome which means we can define
8:20:09
that the palendromes are like an onion where the middle value remains the same and because of the middle values all the
8:20:16
other subsequent values where the values are actually same uh the palendroic property is sustained why I'm giving so
8:20:22
much explanation for that uh is you will see it in the optimal solution and the o in the odd cases we only have one value
8:20:29
as the middle character but inside the even character suppose we are given a value like BB so this is a palendrome in
8:20:36
itself and both values are same because both values are same uh this is an even
8:20:41
length and this is an even length par palendrome now again I decide to add two more characters xx because they both are
8:20:47
same this still remains the palendrome again I add value a a this is also pendum but the moment I add a value that
8:20:53
is different like x and I now this whole thing is not a palendrome but this middle portion still remains a
8:20:59
palendrome. So that is the important property that in case of odd length we we have a middle character of the
8:21:06
palendrum that is a single character and all the other characters has the same value. In case of the even length
8:21:12
palendrome we have two characters that are same. So that is important two characters they are both same and then
8:21:17
all the other characters they are also same as well and a smaller palendrum is forming a larger palendrome. And let's
8:21:24
see that how can we use this property to find an optimal solution. So suppose this is the example we are
8:21:30
given and we need to find the optimal solution for that. The idea is that at any given character we are actually going to see that whether could this be
8:21:36
a middle of any palendrum and if it is the middle of the palendrome we are going to keep on expanding our
8:21:41
palendroic search and we are going to keep adding our answer result. First of all let's see for this character number
8:21:48
C that can the C be part of any middle of the palend palendroic substring or not. Well, we already know that this C
8:21:54
is a substring in itself because if we read it from left or right, we get the same result. And we are also going to
8:21:59
have a variable called answer. So, initial value was zero. Now, because this C so now because the C is a
8:22:04
palendrome in itself, we are going to add the value to our answer as well. Now, we are going to see that whether the C is a middle of the palendrome or
8:22:10
not, which is not. Why? Because if we see the left of the string and right of the uh C, this is actually a null value
8:22:15
and this is A, which means both are not same. So, because both are not same, this is not part of any middle of the
8:22:21
substring. Now we are going to have this value a. Again we are going to repeat the same process. Well a is a palendrome
8:22:27
in itself. Uh so we are going to add the value to our answer first of all. So this becomes two. Now again we are going
8:22:33
to check that whether this a is a middle of any palendrome or not. We also have to check for both the cases that could this be of oddlength palendrome or an
8:22:40
even length palendrome. So for oddlength palendrome like the both left and right value would be same and for even length
8:22:46
palendrome the value would be same with that itself. So first of all we are going to check with this a. So the left
8:22:53
value is c and right value is actually b. So both are not same. Also they are not same of this a and b which means
8:22:59
this is not an oddlength palendrome and even length palendrome. So we are good to go. Now we will move on to the next
8:23:04
value b. Now this next value b is a palendrome in itself. So we will update the value inside our answer to three.
8:23:11
After doing that we are going to check that could this be the middle of any palendrome or not. So we will check the left and right value. Left value is a
8:23:17
and right value is also a. So because these two are same we can define that this B is actually part of the middle of
8:23:23
the palendrum which is of odd length and we are going to keep on expanding our palendrome. So now this B A B so sorry
8:23:31
now this A B A is also palendrome. So we will update our answer immediately. So answer becomes four. Now now again we
8:23:38
will keep on expanding our palendrome. So if we do a left and right over here the left value is C and right value is
8:23:43
actually null. So these two are not same. Because these two are not same we no longer have a palendrome. So we will
8:23:48
break out of the loop. Now again we still have one more character left to check. So again we will check for this
8:23:54
value number A. So A is a palendrome in itself. We will put the answer as five. Then again we will check that whether
8:23:59
this A is a is that a middle of any palendroic string or not. So we check left and right value. Left value is B
8:24:05
and right value is actually null which means these two are not same and they're not same of this A as well. Uh so
8:24:10
immediately we will break out of the loop and we can return uh and the next value over here is actually null which
8:24:16
means we don't have anything. we have reached to the end of the string. So this is the answer we need to return in this case that five would be the answer
8:24:23
and we will return that. Let's see one more example S where we will find the even length uh palendrome. So over here
8:24:30
again we are going to repeat the same process. So first of all we'll take this character number C. Can this C be part
8:24:35
of the any middle of the substring or not? So this is not part of any middle of the substring and we will have an answer variable. So first of all we'll
8:24:42
initialize it to one because C is a substring in itself. Now we will move on to the next value A. So A where A if we
8:24:48
check the left and right pointer left is C and right is B. So these two are not same. So immediately A is also not the
8:24:53
middle of any new palendrome but it is a palendrome in itself. So again we will update the value to two. Now again we
8:24:59
are at this position number B. Now at this position number B if we compare left and right values. So left value is
8:25:05
A and right value is B. So these two are not same but these two are actually same. So we can define this BB to be a
8:25:11
middle of a palendrome. And this is the property we are going to use right. And by the way for this B first of all we'll
8:25:18
update the value to three. And now we have this BB that is a middle of the sub palendrome. Now immediately we will
8:25:24
check the left and right value. So left value is A right value is also A. Again these two are same. So this is also
8:25:30
palendrome. So we will update our answer again. So this becomes four. Now again we will check the left and right value
8:25:35
over here. So left value is C and right value is actually null. So in this case these two are not same. Because these
8:25:40
two are not same, we will break out of the loop and we will say that okay so far we have found something decent. So uh right now again we are at this
8:25:48
position number B. Now remember that this becomes a little bit tricky that it
8:25:53
becomes easy for us to if we check over here this left value is actually B and right value is A. So again these two are
8:25:59
same but we should not fall for this trap because we have already concluded this BB to be a middle of the
8:26:05
palendrome. So we will not consider this one and this is also not a palendrome which means that the answer we will only
8:26:12
update by one and that this value by itself is a palendrum and at the end we
8:26:17
will check for this value number a and a is a palendrome in itself. So we will update the value to be six but in the
8:26:23
left and right there is nothing. So we won't do anything with that and in the end we will return this answer six to be
8:26:29
the final answer. And this is the solution we are going to use to find all the palendromic substrings inside any
8:26:34
given string s. This is the final optimal solution. If we see the time and space complexity in this case, the time
8:26:40
complexity is actually going to be big of n². Why n square? Because it takes us n time to iterate over all the values.
8:26:47
And for any single value, we might have to iterate over all the remaining values. So that takes n² time. But this
8:26:53
is still a big improvement compared to our brute force approach which had the uh n cq. If we see the space complexity
8:27:00
in this case, the space complexity is actually going to be big of n because at any given point we might have to store
8:27:05
all the values of n.
8:27:10
First of all, we are going to initialize a variable called answer and we are going to assign the value as zero. Now we are going to create a for loop and
8:27:16
iterate over the given input. Now we have two possibilities. Any single character inside this given
8:27:22
string s could be the middle value of any oddlength palindrum or an even length palindrum. So we are actually
8:27:27
going to make two calls to our check palendrome method where we are going to return a value that whether this given
8:27:33
string is a palendrome or not and we are going to add that value to our answer variable
8:27:39
and inside this method we are going to pass the value of our string s and we are also going to pass the character
8:27:45
position of the middle variable. So the oddlength palendrome would have the same
8:27:51
middle value. So we will pass on that and for even length we are going to pass two values. So over here we are we will
8:27:58
pass I and we will also pass I + 1 to be the middle characters. Basically after we get out of this loop we should have
8:28:04
our answer ready. So we can simply return that. Now let's create this check palendrome
8:28:11
method and we will initialize a variable called count to count the number of palendromes
8:28:18
we encounter. Now we are going to run a while loop that while the left and right pointer are inbounds or and not out of
8:28:24
bounds and while their character positions are same. So which means they satisfied to be the parent room. If that
8:28:31
is the case, we will keep on updating their values and we will keep on adding our count variable and in the end we
8:28:36
will return the count variable. So let me quickly type it type that.
8:28:42
So this condition defines that whether this given string is a valid palendrome or not. If that is the case, we will
8:28:47
decrement the value of our left pointer. We will increment the value of our right pointer
8:28:53
and we will increment the value of our count variable. And once that is done, once we get out
8:29:00
of this loop, we simply need to return the count variable and that's it. Uh so let's try to run
8:29:06
this code. Okay, seems like our solution is working as expected. Let's submit this code.
8:29:14
and our code runs pretty efficiently and I will be posting this solution in the comments so you can check it out from there. Thank you.
8:29:33
So in this section we are going to learn about two most important coding patterns. This one is searching and
8:29:39
sorting. They have been extremely popular in lots and lots of different type of questions because they are so
8:29:45
versatile and they work pretty much with all the different data structures whether it's array string or Q or tree
8:29:53
no matter what you are always trying to searching for the different elements on how they are presented and you are also
8:30:00
trying to sort the existing set of elements in order to find some meaningful information and I'm pretty
8:30:05
sure that you know what they are so we are just directly going to dive deeper into the questions s associated with
8:30:11
searching and sorting. Hello friends, hope you're having a fantastic day today. So now we are going to do an
8:30:16
awesome lead code problem that is extremely popular and you are guaranteed to encounter this question in one of
8:30:22
your interviews. So without any delay, let's get started. So the read code problem we are going to solve today is
8:30:28
called binary search and we can see that this is a lead code easy problem and also one of the most liked problems on
8:30:34
read code. Now the thing is you are always going to be using binary search in your interviews but this is not going
8:30:40
never going to be the direct question because this is a technique that you have to master. So let's understand that
8:30:46
what the problem statement is asking us to solve. We are given an integer array nums which is sorted in ascending order
8:30:52
which is great and we are also given a target value that we need to find that whether it's present inside the given
8:30:57
array or not. If it is present then we need to return the index position of that target. If it is not present, we
8:31:03
need to return minus one. And we are also being told that we must write this algorithm in go of logarithmic and time
8:31:11
complexity. So let's try to understand what is being asked us to solve. Suppose we are given an input array like this.
8:31:17
We are given the target value to be 9. So in this case we can see that 9 is currently present inside this given
8:31:23
array and it is located on index value number four. So in this case we need to return four as the answer because 9 is
8:31:29
present. Now same in the same problem suppose we are given that uh 10 so 10 is currently not present inside the array
8:31:36
so then we need to return minus one. So this is what the problem is asking us to solve. It is very simple to understand.
8:31:45
So brute force approach is quite straightforward. Suppose we are given the values uh like this and we are being
8:31:51
told that we need to find value number four inside this given array. So all we need to do is we can simply start
8:31:57
iterating over this given array one by one and keep on going until we find the value or we reach to the end of the
8:32:03
array. So in this case since we did find value number four we can return the index position of this value and we can
8:32:11
see that brute force approach works as expected. The thing is if we see time complexity for this brute force approach
8:32:18
this is simply going to be bigo of n u and we need to do things smartly
8:32:26
and for that we need to take care of the property that is currently given to us
8:32:31
uh in this array that this given array is actually sorted. So if we use the sorted portion property of this given
8:32:38
array we can actually solve this problem in logarithmic time. So let's quickly see the optimal solution. So we can see
8:32:43
that 9 is currently present inside this array. Now how we are going to use the
8:32:48
log the sorted property of this is by doing binary search. So what binary
8:32:54
search means is that we are going to take this entire array as whole. We are going to find the middle pointer of this
8:33:00
array and using the middle pointer we will compare that whether this middle pointer is smaller than our target array
8:33:07
or is it greater than our target array. If this middle pointer is smaller than our target array, which means the target
8:33:13
array has to reside on this portion of the given input array. So we can
8:33:19
basically eliminate all of these three characters because they are no longer relevant. And if it is the other case
8:33:25
then we in that case we can eliminate these three characters as well. So we will keep on doing that until we either
8:33:32
reach the target value or we run out of the values to search for. And uh in this
8:33:37
case we are going to initialize our array with having a starting pointer and ending pointer. So currently starting
8:33:43
and ending are going to live at the edges and this is going to allow us to find the middle pointer. So in this case
8:33:49
we can see that the target value is 9. The middle pointer we are able to identify is located at value number six.
8:33:55
So we need to check that whether this value number six if that is greater than or less than. So we can see that six is
8:34:01
less than our target value. So because six is less than our target value, we can say for certainty that the target
8:34:09
value can never reside on the left hand side of our uh given value six. Which means we will have to migrate our start
8:34:16
pointer once again back to six and repeat the same operation. So now our starting pointer is going to live over
8:34:22
here. Ending pointer is still going to live on the same place. And now we are trying to find the middle pointer. Okay.
8:34:28
So we in just one single iteration we eliminated three characters. And this is the pure definition of logarithmic time
8:34:34
complexity. So once again for this uh we are going to find the middle pointer and middle pointer is going to be find at
8:34:42
value number 11. So now the next middle pointer is value number 11. 11 is actually greater than target value which
8:34:48
means that the target value can never reside on the right side of the this 11.
8:34:54
So we can eliminate this character. And now we only have these three values 6 9
8:35:00
and 11. and we are going to mark 11 as our ending pointer. So now once again we
8:35:06
repeat the same operation and try to find the middle value. The middle value is 9 in this case and 9 is actually
8:35:11
equal to target which means the index location of this 9 uh I think it's four.
8:35:17
So this this is what we can return in the answer. And you see that we were
8:35:22
originally given seven different elements. But within just three iteration we were able to find that
8:35:29
where does the middle point where does our target value is present inside the array or not. If it was not present
8:35:34
let's assume that maybe this was value number 10. So we realize that we find the middle pointer and now uh this is
8:35:41
also not uh the target value we are looking for. So now we are going to starting pointer and ending pointer
8:35:47
living next to each other. And once again if we try to find the middle pointer we would not be able to find it. So we could we could have concluded that
8:35:53
now the target value is not present. So in both the ways using binary search is extremely efficient. You are going to be
8:36:00
seeing it the binary search in lot of different problems across your entire
8:36:06
technical interview journey and also across lot of lead code problems. So you must master this technique. If we see
8:36:12
time complexity in this case the time complexity is going to be go of log n because that's what we just did and
8:36:19
space complexity well we did not use any extra data structure or any extra space
8:36:24
apart from storing couple of variables. So this is going to be a constant space complexity as well. Now let's quickly
8:36:30
see the coding solution for this one. Okay. So very first thing we are going
8:36:36
to do is initialize couple of variables. First one is the left pointer and second one is the right pointer. Then we are
8:36:42
going to run a loop that while left is less than or equal to right. We are first of all going to calculate the
8:36:47
middle middle pointer that is going to be the sum of left plus right divided by two. And then we are going to check the
8:36:53
conditions that if the given middle pointer is equal to the target value then whatever the index position is we
8:36:59
can simply return that. If that is not the case and we find out that the given middle pointer is smaller than the
8:37:06
target then we need to update our left pointer to come to the middle pointer. If that is not the case then we need to
8:37:12
update the right pointer and that's it. Basically in the end we should have find the target in this loop if the value is
8:37:19
present. If it is not present we can simply return minus one. So let's try to run this code.
8:37:27
Okay. Seems like our solution is working as as expected. Let's submit this code.
8:37:32
And our code runs 100% faster than all the other solutions. That is because our
8:37:37
code actually runs in constant time or the number of test cases are very small. So that's why and once again the
8:37:44
solution of this code is actually pasted in our uh repository GitHub repository.
8:37:50
So let me quickly show you that where all of the solutions are present. You
8:37:55
can see on this GitHub repository we have over hundreds of different lead code solutions. These are the most
8:38:01
popular, most asked and most important lead code questions. And if you're preparing for your technical interviews,
8:38:07
for sure this can be a great resource for every single one of you. So you can go ahead and check it out. Uh also I
8:38:13
want to show you one more extra resource that is uh this sheet that I have
8:38:18
created. So we you can see that over here I have a couple of list. First list is 130 most popular and most like
8:38:25
technical interview questions of all time. Over here all of these questions are separated based on topic. And I have
8:38:32
also included that how many times these questions were asked at any particular company and what is their difficulty
8:38:38
level is it easy, medium or hard. And for every most of the questions you can see that there are solutions available
8:38:44
as well. So if you want you can go and check it out. On top of it, neat code 150 is one of the most best resources
8:38:52
for technical interview preparation. So I also started working on solving neat code 150 so I can get better at lead
8:38:59
code and also I can create videos that might help other people as well. So over here uh once again these are all the
8:39:06
questions separated based on the topic and difficulty level. Majority of them are solved and the rest would be solved
8:39:12
soon. So you can go and check it out. So uh the both the links are in the description. I hope you find this
8:39:18
resource helpful.
8:39:29
Hello friends, I'm a cloud solutions architect at Microsoft and I like making lead code videos. So today we are going
8:39:35
to solve another very popular lead code video which is find first and last position of elements in a sorted array.
8:39:41
And if we see some of the popular companies where this question has been asked, there are companies like Facebook, Amazon, Microsoft, Bloomberg,
8:39:47
Google, LinkedIn, Apple, Uber, Instacart, Twitter and Tik Tok. So that's why I'm paying my utmost
8:39:53
attention making this video. I hope you also find it informative.
8:39:58
So this is a lead code medium problem and also very well-like problem on lead code. Basically, we are given an integer
8:40:04
array that is sorted in nondereasing or ascending order and we are also given a target value. Now in this sorted array
8:40:11
we need to find out that what is the starting and ending position for this particular target value. Uh if the
8:40:17
target value is not present we need to return minus1 minus1 as the answer. We are also told one more condition that
8:40:23
this has to be running in because of login time which is like logarithmic time. So definitely this is the big clue
8:40:30
that we need to solve this using binary search tree. So over here I have actually taken these two examples and
8:40:37
enlarged them over here. So this is the input array we are given. We can clearly see that all the elements inside the
8:40:43
input array are sorted in ascending order. Uh we are also given the target value to be eight. Now in this case we
8:40:48
need to return the first and last position of 8 that is present inside this given input array. And we can
8:40:55
clearly see that the first occurrence of 8 is here where if we see the index
8:41:00
value the index value is three. So that is going to be part of the answer. And the last position of value number eight
8:41:06
is at index number four. that is also going to be part of the answer. And in this case uh we need to return the first
8:41:12
and last positions of this target value number eight that is present inside this given array which is going to be three
8:41:18
and four. And this is going to be the answer we need to return. Same way if we are suppose we are given the same input
8:41:23
array and this time we are given the target value to be six. Now six is not present inside this entire given array.
8:41:29
So because six is not present we are actually going to return minus1 minus1 as the answer. And this is what we need
8:41:36
to return in this case. So basically this is what the problem is asking us to do. And as the name suggests that find
8:41:42
first and last position of elements in a sorted array. So basically that is what we need to find. Now let's see that what
8:41:48
are going to be the different approaches to solve this problem. Uh the first approach that comes to our mind is a
8:41:53
brute force approach. So in the brute force approach suppose this is the input we are given. We are told that the target value we are trying to find. Okay
8:41:59
let's not put five. Let's put one. Okay. So suppose we are we have the target value one. we need to find. Now in this
8:42:05
case uh we can clearly see that one starts at position number one and ends at position number three. And in this
8:42:12
case the answer is going to be 1 three. So because this is a brute force the we are going to apply the most simple logic
8:42:18
and most simple logic is we will start iterating from the beginning until the point where we reach the target value.
8:42:24
So over here this is not the target value. So we skip to the next element. Now this is a target value that we are
8:42:29
expecting. So because this is the target value, we are going to note it its index position as the answer. So okay, this is
8:42:35
the first value we find as the answer. Now we will keep on iterating to to the next element until either we reach to
8:42:42
the end of this array because it could be possible that all the other values are the target value or we reach to some
8:42:48
value that is not one definitely. So in this case okay we reach over here this
8:42:53
is also one and this is also one. The moment we reach to this value okay this value is not one. So because this value
8:42:59
is not one which means that one value before that has to be the last occurrence of one. So in this case okay
8:43:05
index value for this is four. So 4 - 1 we will have to do three. So in this case three is going to be the last
8:43:11
occurrence of one. And this is the answer we need to return like somehow we keep on iterating and we don't find the
8:43:17
target value. So in that case we need to return minus1 minus1 and uh that this
8:43:23
solution would also give us the correct answer. But the problem with this solution is going to be that if we see time complexity, the time complexity is
8:43:29
actually going to be big of n. And we are explicitly told that we need to solve this problem in logarithmic time
8:43:36
in big of log n. So that is not being satisfied in the brute force approach.
8:43:41
So we'll have to find a better way. Now the question comes that how we are
8:43:48
going to use binary search and how we are going to apply that here. uh we know using the binary search it becomes
8:43:55
pretty easy for us that we actually have a starting value we actually have an ending value we try to find the middle
8:44:01
value. Now depending on the middle value we either remove all the elements on the
8:44:06
right side or we remove all the elements on the left side and we update our starting and ending position keep on
8:44:12
repeating this process until we find the middle value. Now in this case the logic is not quite simple as just finding the
8:44:19
target value. Why? because it could be possible that there are multiple target values and what we are trying to find is
8:44:25
to try to find the first occurrence and also try to find the last occurrence. If we just apply the simple binary search
8:44:32
tree over here, uh things won't work. Why? Let me quickly show it to you. So suppose in this case, okay, starting
8:44:38
position is zero, right? So starting position is zero. Uh ending position is currently five. So ending position is
8:44:44
five. We set up two pointers. Now we try to find the mid value. So mid value in this case is going to be 0 + 5 divid by
8:44:50
2. So 5 divided by 2. If we take the floor value we get the value as 2. So 2 is the middle value which is this in
8:44:57
this case. Right? Now if you see for this array the target we were searching for is one. And immediately we find the
8:45:05
target to be two. But that doesn't give us any meaningful value because uh this
8:45:10
middle value is already a target but it is of no use of us because this is
8:45:15
neither the starting value neither the ending value. So you must be thinking okay there is one simple logic we can
8:45:22
apply over here and that simple logic is that uh the moment we find the middle value we start on traversing on one
8:45:29
direction and eventually we would be find we would be able to find a place where the value by itself is going to be
8:45:38
like the first occurrence. So in this case what happens okay this is the middle value we found now we will start
8:45:43
iterating on the left side. So on the left side we will find okay again this value is one. So still we don't know
8:45:49
whether this is the first occurrence or not. So again we are going to take one one step on the left hand side and again
8:45:56
uh this is value zero. So the moment we find a different value than one we can clearly determine that the previous
8:46:02
value was the first occurrence. So in this case okay we can mark this answer as one. Uh so that is like the first
8:46:08
occurrence and same we are going to repeat the same process for from this middle value to the right hand side to
8:46:13
find the last occurrence. So if we search right hand side okay this is also one. So we don't know that this is the last occurrence or not. But the next we
8:46:21
check okay this value is not one. So definitely this was the last occurrence. So last occurrence in this case is going
8:46:27
to be three. So we mark three as the answer as well and we get the answer. Bingo. So this solution would work and
8:46:33
you would argue that hey uh in average case this works in like big go of login time right but the thing is we are not
8:46:40
concerned with the average case why because so say for an example you take a scenario where we are given an input
8:46:47
array that looks like this and all the values are actually the target value. So suppose target value we are trying to
8:46:53
find is seven and all the values are seven. So what would happen in this case like we would have this starting value
8:46:59
we would have this ending value eventually we found a mid value the mid value in this case is going to be seven.
8:47:04
So now we keep on iterating on the left again on the left and uh we reach to the first position and this is still seven.
8:47:10
So we would identify that hey this seven is actually the beginning point. Okay. So zero has to be part of the answer.
8:47:16
Again we keep on repeating on the right side and keep on doing the same process until we to reach to the last element
8:47:22
which is still seven which is still the target value. This is five. Okay. So this is the answer we need to return.
8:47:27
But if you see time complexity in this case the time complexity would become big of n. Why? Because we keep on
8:47:33
iterating to the next element and uh that is not what we want. We want a strict big of log n time log logarithmic
8:47:41
time. So what is the logic we are going to apply over here. So the logic we are
8:47:46
going to apply is uh that definitely we are going to use the binary search right that's a given fact but we will have to
8:47:52
make some tweaks. Okay. Now I'm going to show you a rough blueprint of the solution we are going
8:47:58
to apply. So suppose this is the array we are given. Now what are the things we know? We know that this array is going
8:48:03
to be sorted in ascending order which means everything on the left hand side is guaranteed to be less than everything
8:48:09
on the right hand side. I mean less than or equal to. We are also given some target element. So now we are going to
8:48:14
first apply the binary search to find target element somewhere. So the logic we are going to use is that okay
8:48:19
depending on the starting and ending value we would be able to find some middle value. Now we will try to see that whether this middle value if that
8:48:26
is less than this target value if that is the case which means that the target lies somewhere over here. If that is not
8:48:33
the case and if we find okay that whether this middle value is actually greater than target value. If that is
8:48:39
the case then the target lies somewhere over here. If both are not cases which
8:48:44
means that the middle value by itself is equal to the target value. So that is
8:48:49
great. But thing is our job doesn't end over here. we are actually trying to find the first occurrence of this target
8:48:55
value and the last occurrence of this target value. So first we are going to be focusing on the first finding the
8:49:01
first occurrence of the target value. How we are going to do it that okay that if suppose for example this middle value
8:49:08
if that is equal to the target value right but the thing is we we are not sure whether it's the first occurrence
8:49:13
or not we can only define that this is the first occurrence if the value before
8:49:19
this is not the target value or uh this
8:49:24
somehow we are we keep on doing like binary search and we find that okay the middle value that we were searching for
8:49:30
was by itself the first value inside the array Okay. And that was the target value. Uh either either of these two
8:49:36
conditions are true then only we can say that that is the first occurrence. Uh so what we are going to do is okay suppose
8:49:42
say for so say for simplicity we find okay this first value to be target value. Okay. So now we will try to see
8:49:49
one value before that uh we again find uh and now we are because we find this
8:49:54
middle value to be target value and we are trying to find the first occurrence. we are guaranteed one thing that the
8:50:02
first occurrence has to be in between these values and not over here. So we
8:50:07
can simply ignore these cases and we can update our end value to come over here and then repeat the same process. So now
8:50:13
what we are going to do is we are going to bring our end value over here again try to find the minimum value uh the
8:50:19
medium value and depending on the s value of the medium value we will be able to find that what is like the first
8:50:25
occurrence. Uh same logic applying we would be able to find the last value and
8:50:31
for the last value logic we are going to use is that if the middle value is equal to target value then if that is at the
8:50:38
position where the next value of that if that is not the target value then we can say that this was the last occurrence of
8:50:45
the target value and we put it in the answer or we somehow find the target value to be the last element by itself.
8:50:52
uh in either of these two cases uh this goes in the answer as the last occurrence. So let's try to understand
8:50:58
this with an example and then it would it would make more things more clear. So again we are continuing with the same
8:51:04
example we are given. Uh now let's okay let's mark starting and ending value. Currently the starting value is equal to
8:51:09
zero. Uh the ending value in this case is five. So if we try to find the middle
8:51:14
value the middle value is going to be 5 divided by two. We are going to take the uh floor value. So which is going to be
8:51:20
two. So this is currently the middle pointer we have. Uh now if we compare the middle point uh lucky in this case
8:51:28
middle point by itself is the target value. So now because this is the target value we are trying to find the first
8:51:34
occurrence. So because we are trying to find the first occurrence we will try to see one value before this target value.
8:51:39
So one value before this target value is also one. Which means that amongst these
8:51:44
places there exist the first occurrence of this target value one. So because of
8:51:49
that now we are going to update our uh end pointer. So now our end pointer position becomes midpoint whatever we
8:51:57
find minus one. So now this becomes the new end pointer. Okay. So currently the end pointer position is 1. So if we do
8:52:04
like 0 + 1 divided by 2 we got 0.5. So basically midpointer is going to be zero
8:52:09
because we are taking the floor value. So now this is the midpointer. If we compare this midpointer with the target
8:52:15
value this midpointer is actually less than target value. So because this is less than target value, we will have to
8:52:21
update our start pointer. So now start pointer, we are actually going to update one position to the right and we are
8:52:27
going to keep on repeating the loop until the point where we find like either the start value crosses end or
8:52:33
either end value crosses start. So currently both are at the same position that is acceptable. So currently the
8:52:39
starting pointer is also one, ending pointer is also one. In this case middle pointer is going to be one definitely
8:52:44
and because this is going to be one. Okay, this value is actually the target value. Now we compare this with its
8:52:51
previous value. The previous value is not target value. So because this previous value is not target value, we can say one thing for sure and that is
8:52:58
that this is the first occurrence of this target value. So first occurrence of the target value, we are going to
8:53:03
mark the index number. So index in this case is going to be one and that we are going to store. Okay, now we are done
8:53:09
half the work. Now we are trying to find the last occurrence. Now for the last occurrence again we are going to repeat
8:53:14
the same logic and we are going to do everything from the beginning. So let me clean this up a bit. Now we are trying
8:53:20
to find the last last occurrence. Now for the last occurrence okay we find the middle value. Middle value is equal to
8:53:26
target value. We compare the next element to the middle value. This is also target value which means that the
8:53:32
last occurrence exist somewhere over here. So which means we will have to update our starting pointer. So when we
8:53:38
update our starting pointer we get the new values I as and also we can ignore
8:53:43
all of these cases. So now okay this is our values. So in this case if we try to
8:53:49
find okay uh we find the middle value to be three is actually greater than our target value. So because of that we will
8:53:55
again have to shift our end pointer on the left hand side. Uh so if we shift our end pointer on the left hand side
8:54:01
our end pointer is going to end up over here. So currently starting and ending value both are located at position
8:54:07
number three. So obviously middle value is also going to be located at position number three. So now this is the middle
8:54:12
pointer. Okay, this is exactly the target value. So that solves one pro one part of the problem. Uh and now we will
8:54:19
try to compare its very next element and that value is not the target value which means that this is the last occurrence
8:54:25
of one. So the value is three. So three we are going to mark as the answer. Uh so now we find okay f is equal to 1 and
8:54:32
f l is equal to 3. So we find both the values and that is what we need to return as the answer and this is the
8:54:39
whole logic we are going to apply over here. If you see the time and space complexity in this case the time complexity is actually going to be bigo
8:54:45
of log n and uh it's pretty self-explanatory that uh in every single
8:54:51
uh equation we are eliminating half of the values on one side to find the correct occurrence player position. So
8:54:58
this is a very good example of using binary search to solve the problem in little bit different manner like the
8:55:04
thing is uh definitely uh underlying concept is a binary search uh and everyone knows that but still this is
8:55:11
doing things a little bit differently and uh I would be jumping to the code now.
8:55:19
Okay. So before we actually start implementing the search range method, first we'll have to define that we
8:55:24
actually need to find like the first and last position of any given element. Right? So we are actually going to
8:55:29
create a helper method for that. And for this particular helper method uh I have named it as find bound and this helper
8:55:37
method is actually going to return the integer value of whatever the bound we need to find. Like now the thing is over
8:55:43
here we need to find the first and last positions. Uh so rather than having two separate methods we are only going to
8:55:49
have one method where as an input we are taking the nums array we are also taking in the target and we are also taking in
8:55:56
a boolean character that is first. So this character would define that whether
8:56:01
we are trying to search like the first occurrence of any particular target element or the last occurrence. So
8:56:08
that's settled now. Uh now we are going to create some helper variables. So, so first we are going to create two
8:56:14
pointers start and end. Uh and we are going to assign their values as zero. Uh and we are also going to create a while
8:56:22
loop that while uh start is actually less than or equal to end. Now inside
8:56:28
the loop first of all we are going to calculate the midpointer. Now with this method there could be two possibilities.
8:56:34
Uh it could be possible that we are trying to find like the first occurrence. So which means in that case
8:56:39
the value for this is first would be true. So first we will calculate for that uh scenario and then we will we
8:56:47
will make the calculations for the second scenario. So what could be the condition that we actually find the
8:56:52
correct value and the condition is that if the mid value if that is equal to the
8:56:59
starting value. So if that is the case or we found out that the nums of mid
8:57:05
minus one is not equal to target. uh if that is the case uh we can also define
8:57:10
this to be true and simply return uh the midpointer as the first occurrence of
8:57:16
the value. If that is not the case basically we will have to uh shift our
8:57:21
search. So every single time we are going to update our end pointer to go one position left of mid. So mid minus
8:57:29
one. Now that takes care of the scenario where we are trying to find the first element. Right? Now for the last element
8:57:34
we will also have to do some calculations. So in order to find the last value basically the condition is
8:57:41
that if either the middle value is equal to the end character or end pointer or
8:57:48
the nums of mid + one is not equal to target. Either of these conditions are
8:57:54
true we can simply return the mid. If that is not the case uh this else condition is trying to find for the last
8:58:01
case. So in that scenario we are actually going to update the value of our start pointer. Now uh we have taken
8:58:08
care of uh most of the things. Now we need to also make changes depending on
8:58:15
the position of mid value. So if that is not equal to target. So if that is the case basically we are again going to
8:58:22
make some changes. So first we are going to have the condition that else if uh the nums of mid if that is greater than
8:58:29
target which means that we need to update the end pointer. If that is not
8:58:34
the case we are simply going to update the start pointer and somehow we get out of the loop and we don't have the answer
8:58:41
yet we can simply return minus one. Now from our main method we are actually going to call the helper method that we
8:58:47
have created and we need to find like the first and last bound. So first we are going to create the first element.
8:58:53
Uh and we are for that we are going to call this uh find bound method. Uh we
8:58:59
are also going to keep a condition that if say for example we get the answer as minus1 we can simply return minus1
8:59:06
minus1 as the answer. And if somehow we do not get minus one in the return which means that first element exist so last
8:59:13
element also has to exist. So we are also going to create another parameter called last to find the last occurrence.
8:59:19
And again we are going to call the same method but this time we are going to keep this parameter as false and uh that
8:59:27
way it would be able to calculate the last value and simply we need to return the new array and add these two entries
8:59:34
of the first and last. Uh I think that should have taken care of all the scenarios. Let's try to run this code.
8:59:42
So over here I actually forgot to enter one critical condition that if the given
8:59:48
mid value if that is equal to uh the target value. So if nums of mid that is
8:59:55
target then only we need to proceed over here. Okay. Now it makes sense. Let's try to run this code.
9:00:01
Okay. Seems like our solution is working as expected. Let's submit this code. And seems like our solution is working as
9:00:07
expected. uh our runtime is actually beats 100% because it's uh the runtime is 0 millisecond and even in terms of
9:00:14
space complexity our calculation is pretty efficient. I think late code changed their UI so that's why we we are
9:00:20
seeing it differently and I will be posting the solution in the comments so you can check it out from there. Thank you.
9:00:32
Hello friends. So today we are going to do an awesome interview question that has been asked in companies like Facebook, Microsoft, Amazon, Apple,
9:00:39
LinkedIn, Google and bunch of more. So without any delay, let's get started. So the lead code problem we are going to do
9:00:45
today is called merge sorted array. And you can see that this is a very well-like lead code problem and also
9:00:51
lead code easy problem. Now we are simply given two values of two arrays
9:00:56
called nums one and nums 2. And we are being told that these are sorted in nondereasing or increasing order. Which
9:01:02
means we already have two sorted array called nums one and nums 2. And now from the name we can judge that we want to
9:01:09
create an array that contains values from all the values that are currently present in nums one plus all the values
9:01:15
that are currently present in nums 2. And this array also needs to be sorted.
9:01:21
That is the whole ask of this entire problem. Nothing nothing much. Uh so first let's try to understand this with
9:01:27
an example. Suppose we are given nums one array that is looks like 1 3 and five. Okay. And we are given nums two
9:01:33
array that looks like 2 4 and 6. So obviously we need to create a sorted array that is going to be combination of
9:01:39
these two arrays. And we just need to make sure that this is also sorted. So answer is going to be 1 2 3 4 5 6. This
9:01:47
is going to be the sorted array that is combination of these two. But for this problem just to make it like little bit
9:01:54
spicy little bit tweaky they they gave us like few weird combination. So what
9:02:00
they have told us that is that we do not need to create this whole new or brand
9:02:05
new array. What we need to do is we need to combine these two values but we need
9:02:11
to put all of these values in just nums one array. Now the first question comes to our mind is that hey this nums one
9:02:17
only contains three elements. How can we put six elements inside this nums one
9:02:22
array? If we have to do that, we will have to basically just expand the array and create a new array and do all sorts
9:02:29
of migrate operations. But the thing is what they have actually done is that in
9:02:34
this kind of problem instead of giving us the input like this 1 2 3 uh sorry 1
9:02:40
3 5 they are also given us three zeros and the trailing end of one or nums one
9:02:46
array and nums 2 array is going to contain values like this. on top of it they are also providing us two extra
9:02:53
values. So first value is called m and second value is called n and both this m
9:02:59
and n represents is the number of values that are currently present inside this nums one array. Now by looking at nums
9:03:06
one array we can see that there are actually six values present. But for our our case we only need these three
9:03:13
values. These three are just simple placeholders that are currently present inside our array. they actually don't
9:03:19
serve any purpose. So for this nums one array this value number n would be value
9:03:25
number three and for this nums 2 array this value number n would be value number two. This would say that nums one
9:03:31
oh sorry this would also be three. So this would say that nums one array contains three elements. This would say
9:03:37
that nums 2 array contains three elements. And if we see the total size
9:03:42
of this nums one, it is a it is able to store six values which means this stored
9:03:48
array would actually be stored in this nums one instead of uh creating a
9:03:53
separate array like this. And that's it. I know understanding this problem is actually more complicated than solving
9:04:00
this problem. So let's try to see how we can solve this. And yes, we can exactly
9:04:05
solve the way you are thinking, the way we would logically do. But we are just going to use pointers in this case to
9:04:11
solve this problem. And uh we are also going to do couple of things here and there in like different order uh for the
9:04:18
ease of simplicity for our problem. So what we are going to do is let's assume with the same one let's say that we are
9:04:25
given this nums one array and this contains three three elements that is 1 3 and five and the rest uh elements are
9:04:34
zeros okay so it contains let's say let's say three zeros okay and we are
9:04:39
given this nums two array and this contains three elements and these three elements are 2 4 and six okay and we all
9:04:49
know what the answer is going to be. But what now what we need to do is at any
9:04:54
given at this particular position the value needs to be the highest value that
9:05:00
is currently present amongst both of these arrays and the highest value can only be present at the end of this
9:05:07
location or at the end of this location because we are told that these are sorted values and because these are
9:05:15
sorted values. So these two are the maximum values present amongst each array. So the value that goes in the
9:05:22
last element would be the maximum value amongst these two value and then all we need to do is whichever value we put
9:05:29
over here we need to take care. So let's assume that we decide that we need to put value number six in this case. Okay.
9:05:35
So let's update value number six over here. And we can say that okay because we are six putting six over here. Now
9:05:41
this six is under no consideration. So now we need to check for the second
9:05:48
largest value. We need to check the second value in this ar this array and
9:05:53
the very last value in this array. Whichever is greater we are going to put that. So we are going to put value
9:05:58
number five here and get rid of five. And same way if we keep on repeating the same process we can simply fill out our
9:06:05
array and we can put all the values in nums one. Now the question would come to you that hey why are we starting from
9:06:11
the back and why are we not starting from the beginning and the only reason we are starting from the back is because
9:06:18
we don't have to do lot of overwrite operations because we are being told that these three values are already zero
9:06:24
they are not going to be part of our conclusion and we can simply update the values rather than thinking about
9:06:31
changing the values and then storing the temporary value because imagine if we have to make changes over here. Imagine
9:06:37
that uh instead in this case let's assume that uh this first value is value
9:06:42
number two and this value is value number one and now we are trying to find the smallest value in this case we will
9:06:47
have to put one over here and then we will have to store this two somewhere else and then we will have to repeat the
9:06:52
same pro operation for these two values and so on and so forth. So in order to make sure that we don't fall into the
9:06:59
scenario of uh making updates, we are simply doing that. And now let's see
9:07:04
that what is going to be the actual way uh I just explain you the method. The
9:07:09
only thing we are going to do is we are going to have three pointers. Uh and the first pointer is going to be the last
9:07:15
value that is currently present for nums one. So for this our example 1 3 5 and
9:07:21
then 0 0 and 0. Okay. So our first pointer is going to live at this point and we can just name it as I. Now for
9:07:29
this uh second pointer that is going to be our uh value of m and n. Okay. So
9:07:37
let's say that these are the values we have. So this is where the m pointer is going to live and this is where the n
9:07:43
pointer is going to live and this is this would be the same value that we can get get from the values m and n. And now
9:07:50
for the i location we need to check that whichever value is greater compared to m and end until these values reaches to
9:07:57
the very first element. So this is going to be our loop condition. We first check okay. So currently n is greater because
9:08:04
n is greater we are going to move value number six in this place and we are
9:08:09
going to uh migrate this pointer number n to come over here once again for and
9:08:15
we are also going to migrate value number i. So now I is currently present on this pointer. Once again we are going
9:08:21
to repeat the same pointer same process. Now five is greater. So we are going to update the value of pointer M. We are
9:08:27
going to add value number five over here. And we are going to again repeat the same process. So now this is our M
9:08:33
and this is our N once again. And we also update the E pointer to come at the one location on the side on the left
9:08:40
side. And if we keep on repeating the same process, eventually we would have our n1 that looks like 1 2 3 4 5 and 6.
9:08:48
And this is going to be the answer. This is a very simple problem. So that's why the answer is also very simple. If we
9:08:54
see time and space complexity, time complexity is going to be big of n where n is the number of total values that are
9:09:01
present in both n1 and n2 items. If we see space complexity, well, space complexity is going to be big of one
9:09:07
because apart from storing couple of pointers, we are not using any additional values. To solve this problem, the very first thing we are
9:09:13
doing is initializing three pointers. Then we are running our while loop that while pointer 2 does not reach to the
9:09:19
very first index of the nums one array, we are going to keep repeating the same process. So first we are going to check
9:09:24
that whichever value is greater is going to be placed on the e location and
9:09:30
whichever uh value that we picked out we are going to reduce that pointer. Uh at
9:09:35
the same time in either case we are always going to decrease the pointer of i location and eventually we would have
9:09:43
all the values sorted in the nums one array and uh this is the code. So let's try to run the code. Okay seems like the
9:09:50
solution is working. Let's submit this code. and our code runs 100% faster than all
9:09:56
the other solutions which is pretty good and pretty awesome. So I will be posting the solution in our GitHub repository
9:10:02
and the link is in the description so you can check it out from there. Thank you.
9:10:14
Hello friends, hope you're having a fantastic day today. So in this video we are not only going to solve a very
9:10:20
popular lead code problem. We are also going to learn a brand new Dutch national flag algorithm. And this
9:10:26
algorithm has actually been developed by Dysters our very own god of shortest path algorithm. So without any delay
9:10:33
let's get started. So the name of the problem is called
9:10:39
sort colors and you can see that this is a very popular lead code medium problem and this problem has been asked in bunch
9:10:46
of companies like Amazon, Google, Microsoft all of them. So let's try to understand the problem statement.
9:10:51
Basically we are given an array nums with n objects and the each of the
9:10:56
object has been marked as one separate color red or blue and we need to sort
9:11:02
these in place which means in bigo of one space complexity in such a manner
9:11:08
that the same colors are adjacent to each other and the order of the color has to be red then white and then blue.
9:11:15
Now we are being told that uh the because we are given an integer array each integer is represented by a color
9:11:22
and this is actually the flag of Dutch or Dutch nation Netherlands. Now let's
9:11:28
try to understand this with uh some of the real life examples. So suppose we are given an integer array like this.
9:11:35
Now we need to sort this array in such a manner that each number is next to each
9:11:40
other like its color type and also we need to follow the sequence of 012 or red white and blue color sequence. Okay.
9:11:48
So first is going to be zero because we only have one zero then we have two ones. So in the answer we are going to mark two ones and then two twos. So this
9:11:55
is going to be the solution that we need to return. Now you must be thinking that hey this
9:12:01
is a very simple problem. Why is this even a lead code problem? Because in this given array, if you just apply like
9:12:09
sort function or a sort library that every single language has like Java, Python, you name it, then it can
9:12:15
generate this answer pretty easily in like big of n login time and you don't have to do anything. But there are a
9:12:22
couple of caveats to that. Number one, we are being told that we must solve this problem without using the library
9:12:28
sort function. So that is number one. Number two is that the library sort function actually solve this problem in
9:12:34
big off and login time. But I'm going to show you how to solve this problem in actually even faster in big of end time
9:12:41
using the Dutch national flag algorithm. Now first if we want to see the brute force approach or if you want to see
9:12:47
like some more inefficient methods uh there are all there like in the brute force you just iterate one by one and
9:12:54
find each values and then start sorting them. So brute force is going to yield in big of n square time complexity. The
9:13:01
better or more efficient approach is using the sorting function or merge sort or quick sort that is going to yield big
9:13:07
of n log n time complexity. But now let's just see that what is going to be the optimal solution for this problem.
9:13:14
So what we are going to do is instead of taking advantage of uh any of the
9:13:20
existing library functions, we are going to take the advantage of the fact that we only need to sort three distinct
9:13:27
items. Which means in either cases the number of possibilities that let's say
9:13:34
that if this is the first section and this is the second section, the third section has to be only this much amount.
9:13:42
Right? There is a there is going to be a very clear distinct boundary. It can be anything. It can be like the first value
9:13:48
is only just one value. The second value is only these four values. Then also the
9:13:54
all the middle portion or all the remaining values are going to be value number one. So we are going to take
9:14:00
advantage of this fact in order to achieve this fact. What are the information we need? Well, number one
9:14:05
information we need is that where does zero end? So because currently we are
9:14:11
trying to sort 0 1 and two three values right. So we will know that where does 0 end. We will also know that where does
9:14:18
two start and all the portion in between has to be one and using this fact we
9:14:25
should be able to solve this problem in big of end time. So let's try to see the example of what I'm suggesting and then
9:14:31
it would make things much more clear. So let me just clean this up a bit. Let's assume that currently we are given this
9:14:38
array and let's add some random values, right? So let's add values like 1 2 0 0
9:14:44
1 and uh one. Okay, suppose this these are the values we are currently given.
9:14:50
Uh let me just add a couple of more values to make it uh more like longer
9:14:56
and let's just add like uh 2 1 and 2. Okay, suppose these are the values currently we are given. Now what I'm
9:15:03
suggesting is that we leverage three pointers. So first pointer is going to be called left pointer. This pointer is
9:15:10
going to keep track that where does the initial zeros needs to be placed or
9:15:16
where do they so if we encounter zero at any moment. This is the position where
9:15:22
this zero has to be entered in the existing array. Next we are going to keep track of the right pointer or a
9:15:28
high pointer. So this is a low pointer. Now let's just mark this as high pointer. So next we have an h pointer
9:15:35
and this h pointer is going to take the ind index position where if we at any
9:15:42
given time encounter value number two it has to go on that place and then third
9:15:47
we are going to have a current pointer. So this current pointer is going to help us iterate over the given existing
9:15:53
array. Now this is the logic. Now let's try to understand what I mean. So initial position would be that currently
9:16:00
left pointer is located at the very first position because imagine at any given moment we encounter a zero that
9:16:07
zero has to be at the very first index location. So this value has to be zero
9:16:12
if there exists zero. If there does not exist zero then that's fine. Uh same way if there exist a two at least the two
9:16:20
has to be here or if or if it is not here then there has there should not be
9:16:26
any two in the entire array in the sorted position. So for the h we are going to place at the end and since for
9:16:33
the current array we are just taking its help to iterate over we are going to have initial position for current array
9:16:39
at the very first location. Now the logic is we will first check okay whether whether this value is zero or
9:16:45
two. Okay if currently this value is neither zero nor two. So we are simply
9:16:50
going to move our current pointer one step forward. Moving current pointer one step forward. Now currently this value
9:16:58
is two. Now because this value is two we will have to update into or we will have
9:17:03
to swap values with current age pointer. Okay. So uh I think this let's just make
9:17:10
this value something else. Let's just make this value zero. So because I didn't want it to have h value at
9:17:16
pointer number two. Okay. Uh and now let's just so we realize that this value
9:17:21
is two. Because this value is two, we will have to swap it with the position of h. So current position of h is zero.
9:17:29
So we are simply going to do a swap operation. So let's just swap these two values. Currently this value is zero and
9:17:35
this value is two. And now once again we will because we know that this is the
9:17:40
position where we already have a two which means next time if we encounter two two has to be placed one step before
9:17:47
that. So we are going to update the value of our age pointer and we are going to keep on repeating the same
9:17:53
process. Now notice that we we haven't updated the C position at this moment
9:17:58
because we did not know what value could be coming from from this H side and if
9:18:03
the value was zero we would have to iterate it over. So because in this case this was the same case because this
9:18:09
value was zero. So now we realize that current is located at the zero position. So if we encounter zero position we will
9:18:16
have to place it where current L stands and then update the value of L in the same manner. So now we are going to swap
9:18:22
these two values. This value is zero. This value is one. Now we know that this first value is guaranteed zero. So we
9:18:28
are going to update the value of our lower pointer. And when we do that, we are going to have encounter L over here.
9:18:36
And now since we already processed this node, we are we can move forward to the next node because we already know with C
9:18:43
that this value was not zero. So the only position was that this could have been one or two. If it is one, then we
9:18:49
just move forward. If it is two then we would have replaced it with the last value. Okay. So now let's just once
9:18:55
again go to this position and currently this is our C. Repeating the same process. We've identified that this
9:19:02
value is zero. So now we will have to swap with swap it with the current L value. So we are going to replace like
9:19:08
that and we are going to update the position of L and we are also going to update the position of C. So now we have
9:19:14
our C located at this zero position. Once again we are going to repeat the same process and we are going to swap
9:19:20
operations. So 0 and 1. Now L comes over here and C comes over here. So let's
9:19:26
just update these. Okay. Now this value is one. So we don't care. Just we just move to the next value. This value is
9:19:32
one. Once again we don't care. We just move move on to the next value. And now our C is currently located at this
9:19:39
position. So now this value is two. Because we find a value that to be two. we will have to replace it with the
9:19:45
value of h. So we are going to do that replacement and we are going to have our H value loc
9:19:53
be be located over here and we still have our C value over here because what
9:19:58
if this value could have been zero though it's not but if it was zero we would still have to process it and once
9:20:05
again we are going to in the next iteration iteration see okay so this value is one because this value is one
9:20:10
now we are going to move to the next value and the moment we identify that either the given current location and
9:20:17
the location of H is equal to each each other then we can end the loop or we've
9:20:22
identified that this L and H are like equal to each each other then also we can end the loop and now if you see the
9:20:29
final answer you can see that this array is completely sorted so first three values are zero next four values are one
9:20:37
and next two values are simply two and this is the sorted answer that we need
9:20:42
to return now you see that how beautiful this solution looks and if We see time and space complexity. In order to do
9:20:48
solve this problem in in terms of time complexity, we are simply solving in big of end time which is excellent. And in
9:20:55
terms of space complexity, apart from storing few pointers, we are not using any extra space. So we are also solving
9:21:03
this problem in big of one space complexity. This is so great because typically whenever we see sorting, we
9:21:10
always solve sorting using n log n time. But for distinctively purpose of sorting
9:21:17
just three distinct variables we are being gifted this by Dyster this Dutch
9:21:23
national flag algorithm and uh this is how we can solve this one. Now let's try
9:21:28
to implement this using the code. Okay. So here is the solution for our
9:21:34
code. So first we are initializing three pointers. First pointer is low pointer. Next pointer is high pointer that is
9:21:40
located at the very last of the given array. And then we have the current pointer that we are going to use to iterate over all the values. Now we have
9:21:47
the condition that while current is less than or equal to high we are going to keep on repeating the same process. First we are checking that if the given
9:21:54
current position the value element is zero. If the current value is zero then we will have to swap it with whatever
9:22:00
the location of this low pointer is. So we are going to have a helper method swap that is simply going to allow us to
9:22:07
swap two values. So we are going to swap the current value with the position of
9:22:12
low then we are going to increment low and we are also going to increment current. If that is not the case and for
9:22:18
some given given moment if the current value is equal to two then we are going to swap number of current with the high
9:22:25
value at the very end and we are only going to reduce the value of high. We are not going to increase the value of
9:22:31
current because that number might could be zero. So we will have to repeat and redo the same operation. And last if
9:22:38
both of the these are not case which means this current value is value number one. So we can simply update or update
9:22:45
the value of the current pointer. And this is the whole solution. Now let's try to run this code.
9:22:51
Seems like our solution is working as expected. Let's submit this code.
9:22:57
And our code runs 100% faster than all the other solutions which is pretty
9:23:03
awesome. And in terms of memory usage, we are also much more efficient compared to lot of other problems. So once again,
9:23:09
I would be posting this solution in our GitHub repository. So you can check it out from there. Thank you.
9:23:23
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better at technical interviews. Keeping with
9:23:30
that goal in mind, today we are going to do a very interesting lead code problem called majority element. And if we see
9:23:35
some of the popular companies who have already asked this question, there are companies like Amazon, Bloomberg, Adobe, Google, Apple, Microsoft, Uber,
9:23:42
Facebook, Bite, Dance and Flipkart. So that's why I'm paying my utmost attention. I hope you also enjoy the
9:23:47
video. This is a lead code easy problem and also very well-like problem on lead
9:23:52
code. Basically we are given an integer array of the size n and we need to return the majority element. Now we are
9:23:59
given the definition of what a m majority element is and basically any elements that appears more than half of
9:24:06
the times in the given array we can consider that to be a majority element and we are guaranteed that the majority
9:24:13
element always exist inside any given array. So this is the whole problem statement. If we see couple of examples
9:24:19
in this case the given array is of size three and the element three actually appear twice which means more than half
9:24:25
of the times. So basically three is the answer we need to return. If we take a look at the second example basically the
9:24:32
element two appears four times and element one appear three times. So since
9:24:38
two is appearing like more than half of the times we are going to return two as the answer. And this is the whole
9:24:44
problem statement. This is very simple problem to understand and basically the answer is also going to be very simple.
9:24:50
Suppose we are given an input n uh that looks like this one. The we are going to use the same example. So if the given
9:24:56
input is like 2 2 1 1 and 1 and also 2 and 2. So in this case the answer is
9:25:02
quite simple. Whichever element is occurring more than half of the times or most of the times is going to be the
9:25:10
answer. We already know that what is the size of this given n. In this case, the size of this given n is actually seven.
9:25:16
Okay. So, we already know that the size is 7, which means any element has to
9:25:21
appear more than 7 divided by 2. So, 7 divided by two is going to be 3.5. So,
9:25:26
if we use like the floor value basically the element has to appear more than
9:25:32
three times, which means any element that appears four or more times is going
9:25:37
to be the answer. Now, the logic is quite simple. We are simply going to using this n create a hashmap. Now
9:25:45
inside this hashmap we are going to use two elements or two items. First item is the key and second item is the value. As
9:25:52
the key we are going to use the unique values that are present inside this given input. So if the value has not
9:25:58
occurred not appeared we will create a new entry inside the hashmap. If the value has already appeared, we will uh
9:26:04
just use that value and as its subsequent value, we are going to basically count the number of
9:26:10
occurrences. So that is going to give us that how many times any particular number has appeared. If we just keep
9:26:16
iterating for this particular example, first we will see value number two does not does not exist. So we will create a
9:26:22
new entry over here called two. And currently we have only received one occurrence of two. Then again two. So
9:26:29
two already exist. And since it already exists, we are going to update the number of occurrences. So currently two
9:26:34
has two occurrence. Now the value is one. Uh so one does not have any occurrence. So basically we are going to
9:26:39
add one more entry one over here. And current occurrence is one. Now at this particular position currently one
9:26:45
appears two times. So again we are going to have one appearing two times and then eventually one would appear three times.
9:26:51
So basically one is going to appear three times. Now we are done with all of these elements. Now currently we are at
9:26:57
this particular position. So basically two is appearing again. So now two is going to appear two more times which
9:27:02
means eventually the hashmap is only going to have two values which uh these
9:27:08
entries and we can clearly see that two is the value that appears four times. So two has to be the majority element and
9:27:15
we are going to return two as the answer. And this is a very simple problem. So that is why this is a easy
9:27:20
problem. And if we see time and space complexity in this case the basically the time complexity is actually going to be big of n and the space complexity is
9:27:27
also going to be big of n because we will have to create this new additional hashmap. So now let's move on to the
9:27:33
coding. So today I'm running short on time. So basically I'm just going to explain the
9:27:38
code rather than uh spend time entirely writing it. So in this code basically we
9:27:43
are use we are using a separate helper method called count nums that takes in the uh any input integer array and then
9:27:51
we use uh we create a new hashmap and basically we return a hashmap that
9:27:57
contains uh the number of occurrences of any particular numbers input array. So
9:28:02
what we are doing is first of all we are initializing a counts hashmap. Now inside the counts hashm we are iterating
9:28:08
over the given input nums and we are checking that if the if it contains the key basically we add uh we uh create a
9:28:17
new value and add its occurrence as one if the key already exist we simply uh
9:28:22
update the number of count or like basically we update the number of occurrences inside the hashmap and then
9:28:28
in the end we return the counts hashmap that contains the values of all the
9:28:34
unique ID unique values inside the nums array and also their occurrences. After that from our main method majority
9:28:41
element method basically we initialize a new hashmap and we call our count nums
9:28:47
method with the nums as the input. So this is going to populate our counts array. Once the count array has been
9:28:53
populated, our aim is to find the value that contains the most uh occurrences.
9:29:00
So basically we are simply going to create a new uh majority entry array and
9:29:06
we are going to run a for loop for the given uh input array and we are going to
9:29:12
check that which uh element contains the most entries and whichever it is we are
9:29:18
simply going to add that and in the end we are going to return that particular element and that's it. Let's try to run
9:29:25
this code. Okay, seems like our solution is working
9:29:32
as expected. Let's submit this code. And our code runs decently efficiently compared to other solutions because for
9:29:38
this particular solution, there can be like at least 10 different ways you can solve this problem and some ways are
9:29:43
much more efficient. So you can if you put some thought thought to it, you can also find the solution. Now, as always,
9:29:49
I'm going to post this in the comments so you can check it out from there. Thank you.
9:30:00
Hello friends, hope you're having a fantastic day today. So now we are going to do an awesome lead code problem. So
9:30:06
without any delay, let's get started. So the lead code problem we are going to solve today is called search in a 2D
9:30:13
matrix. Now we can see that this one is a lead code medium problem and also an extremely well-like problem on lead
9:30:18
code. Also really popular amongst top tier IT companies. Basically we are given an M crossN integer matrix and we
9:30:25
are told that it contains two important properties. First property is that each
9:30:31
row is sorted in nondereasing order and next thing is that the first integer of
9:30:36
each row is greater than the last integer of previous row which means even
9:30:41
the columns are also going to be sorted in an increasing order. Now we are given
9:30:46
an integer target and we need to return true if the target exists inside this given matrix and false if it is not
9:30:53
present inside the matrix. Also we are told to solve this problem in go of logarithmic m cross n time complexity.
9:31:00
So now let's try to understand this with an example. Suppose this is an m cross n matrix we are given where m is equal to
9:31:06
3 and n is equal to 4 and we are told that target value is three. So now let's
9:31:11
first quickly assess the properties. We can see that every single row is in sorted order. And we are also being told
9:31:18
that the last element of any particular row is smaller than the next element
9:31:23
inside this uh next row. And so that eventually makes the columns sorted as
9:31:29
well. Okay. And we can see that in this case this three is clearly present inside this given mross in matrix. So we
9:31:35
need to return true that saying that the three is present. But if we are being asked the target to be like something
9:31:41
like 37 then that is not present. So we need to return false. Okay. So let's try to quickly see that what are the
9:31:48
different approaches we can take to solve this problem.
9:31:54
For the brute force solution we don't need to do anything since this is an M crossN matrix. All we can do is just
9:32:01
simply iterate over the given matrix one by one in a normal sequence which which
9:32:06
can be done using two loops and then try to see if the target value is present or
9:32:12
not. If the target value is present return the true immediately and if we don't find and we reach to the end of
9:32:17
this given uh list or given matrix and we don't find the target value then we need to return false. This brute force
9:32:25
solution would work as expected. But the thing is the time complexity is going to be bigger of m cross n because we are
9:32:31
iterating over all of these 12 characters that are present inside the matrix. So we need to speed things up.
9:32:41
Number one thing I'm suggesting is that we know the target value we are trying to find is three. We also know that the
9:32:49
entire rows are for sure sorted. We also know that all of the columns are also
9:32:54
sorted. So one approach we can take is that we compare the columns and based on
9:33:01
the column values we check that under which row should this target value be
9:33:07
present at. So we can clearly see that when we compare the first element in this column versus the first element
9:33:14
sorry first element in this row versus the first element in this row. We can see that the target value three lies
9:33:22
somewhere between column one and uh sorry row one and row two. Which means if the target value is present it has to
9:33:29
be present inside this first row. So once we find that information after that
9:33:35
all we need to do is just simply do a binary search in this operation. So now
9:33:41
we only have one row that we need to worry about. So now we can actually solve this
9:33:46
problem using a simple binary search where all we have is a starting pointer and ending pointer. The target value we
9:33:52
are given is three. So we first try to find the middle pointer. Middle pointer in this case is going to be five. So
9:33:58
this is not the target value and the target value is less than the middle pointer we find which means target value
9:34:04
has to reside somewhere over here. So once again we repeat the same operation. We update our end pointer and then once
9:34:11
again we do the binary search we find the middle pointer and then we simply return saying that yes true the given
9:34:17
target value is present inside the given list. So let's try to see that what is going to be the time complexity in this
9:34:24
case. So time complexity would be inside the given corresponding row we will have to do and log n cross m work. So this
9:34:32
solution would give us the desired result. But the thing is we are doing an intermediary step in between to solve
9:34:38
this problem. So let's try to see that do we have a more optimal solution than
9:34:43
this one as well. And yes we actually have a better optimal solution.
9:34:51
The idea is we already know that every single rows are sorted. We also know
9:34:58
that every single columns are sorted which means the last value of any row is
9:35:03
always going to be less than the first value of the subsequent row. So logically instead of treating this as a
9:35:10
2D matrix if we just try to understand this in a onedimensional direction we
9:35:16
can actually see that this is a perfect example of completely sorted one 1D
9:35:21
array that is currently represented inside the 2D environment and we can
9:35:27
plot all of these 12 values inside this given graph. This is just a
9:35:32
one-dimensional representation of this 2D array and we can see that this is a fully sorted array. Now if we have to
9:35:39
find the target value let's say three in this case the solution becomes quite obvious. All we need to do is just a
9:35:45
normal binary search and we can we should be able to find the result. But the thing is we don't want to create an
9:35:51
additional array. We want to do the binary search treating as if this 2D array was 1D array in this one. So once
9:35:59
again we can also do that. For that all we need to do is just we might have to play around with the starting and ending
9:36:05
pointers. So initially our starting pointer is going to reside over here and our ending pointer is going to reside
9:36:11
over here. We will need to find the middle pointers. So now if you have to find the midpointer the 16 is going to
9:36:17
be the midpointer. So compare 16 with our target value. And we can see that the uh target value is actually smaller
9:36:24
than the midpointer we find which means we will have to update our end pointer to come one value before the midpointer
9:36:30
because this is also not the target value. So once again now we have our new starting pointer uh starting pointer is
9:36:37
the same and we have our new ending pointer. Once again we are going to find the mid value. Mid value in this case
9:36:42
would be value number five. Once again we can see that because this value number five is greater. So once again we
9:36:48
are going to update our end pointer. So end pointer is going to be over here. Start pointer is going to be over here.
9:36:53
Once again we do the binary search and we should be able to find the target value to be value number three. And that's it. This is what we need to do.
9:37:00
And this is the much better approach than brute force approach. And also a
9:37:05
step improvement on our better approach that we saw. Time complexity for sure it is going to be big of log n m cross n
9:37:14
and we are not using any extra space. So space complexity is going to be constant space which means this is a really good
9:37:21
approach. And now let's quickly see the coding solution for this one.
9:37:28
So first of all we are going to define our M and N based on the given matrix value. We are also going to initialize
9:37:34
two variables left pointer and right pointer. Left pointer is going to be at the very first position inside the given
9:37:39
matrix. Right pointer is going to be on the very last position of the given matrix. Then we are going to run our
9:37:45
while loop. During the while loop, first thing we are going to do is to find our midpointer. After finding the midpointer, we will also have to point
9:37:53
that mid value inside our given matrix because remember the midpointer is a
9:37:58
single 1D value. Meanwhile, the uh we are given the 2D matrix. So that we can
9:38:03
do by doing the division of midpointer with the value 9 and doing the
9:38:11
modulo with nine or finding the remainder value. So this is going to give us the exact value of the mid what
9:38:19
the midpointer should be uh in a 2D array and then we simply do our binary
9:38:25
search and based on that we update and manipulate the uh left pointer and right pointer values and in the end if we do
9:38:31
find the target value it should have been returned through here. If it is not present then we can simply return false.
9:38:37
So let's try to run this code. Okay, seems like our solution is working
9:38:43
as expected. Let's submit this code
9:38:49
and our code runs 100% faster than all the other solutions which is pretty awesome. This is also an excellent use
9:38:56
of space complexity as well. So once again the solution is present in the GitHub repository that we have created
9:39:02
and the link is in the description. You should be able to find it from there.
9:39:15
Today we are going to do find minimum in a rotated sorted array. And if we see some of the companies where I want to
9:39:20
get a job who already asked this question, there are companies like Microsoft, Amazon, Uber, Facebook, Apple, Bloomberg, Google and Tik Tok. So
9:39:27
that's why I'm paying my atmost attention. I hope you also enjoy the video.
9:39:32
So this is a lead code medium problem and basically we need to find the minimum inside a rotated sorted array.
9:39:38
Now you will ask that what does a rotated sorted array means. We are actually given some definition of what a
9:39:44
rotated sorted array is. If you want you can iterate over this definition. But the thing is let me quickly show it to
9:39:49
you by an example. Basically we are originally given a sorted array. Now for this sorted array if we take the
9:39:56
rightmost element and put it on the leftmost position and all the other subsequent elements we flip it one side
9:40:02
on the right side we can determine this to be rotated one time. So if I take this original sorted array and if I
9:40:10
rotate one time so one time rotated array is going to look like this. You
9:40:15
can see that this five that was originally at the rightmost position has been flipped to the leftmost position
9:40:20
and all the other values we put shifted them one position on the right. Now if I uh rotate this one more time so
9:40:27
eventually I would rot I would have rotated this array to two times. Basically the result I would get is
9:40:33
going to look like this that where the first two values are four and five and then we have 1 2 and three. Now over
9:40:39
here this four that was originally over here that came to this place. Now we can rotate it like three times, four times,
9:40:46
as many times as we want. Like we can only rotate it up until five uh five times because there are only five
9:40:51
elements. Now basically in any rotated array we need to find that what is the
9:40:57
minimum value that is present in it. So if we try to understand this with an example over here we are given some
9:41:04
array uh where the original version of array was 1 2 3 4 5 that got rotated
9:41:09
three times and we were given this as the input. Now if we see the minimum value in this case is one. So we need to
9:41:15
return one as the answer. We are also given one key important detail that we have to find that we must write an
9:41:22
algorithm that runs in bigo of log and time. So that is the key part. First
9:41:28
let's see that what is going to be the brute force approach to solve this problem. Well the brute force approach that comes to our mind is that why don't
9:41:34
we start iterating over the given array. we have a variable called min or answer or whatever you want to call it and then
9:41:41
uh we start iterating over all the subsequent elements one at a time and whenever we find a lower value basically
9:41:47
we update that in the min variable. So eventually when we start iterating when we would have completed iteration we
9:41:54
would find the value one to be the lowest value that we can find inside this array and that we are going to
9:42:00
return as the answer. This solution leads us to the correct answer. There are no issues with this one. But why
9:42:06
this brute brute force solution does not work in your interviewer interview or anywhere else is because this solution
9:42:12
actually happens in big go of end time because we are iterating over all the n elements and we were explicitly told
9:42:18
that we need to solve this problem in big go of log time. So that's why this brute force solution won't work. Now
9:42:24
whenever we see log and solution immediate thing that comes to our mind is that we are going to use binary
9:42:29
search right and that is true that we are going to use binary search in this case but before we do that let's make
9:42:35
some logic clear. Well, the key part of the logic we have
9:42:42
is that if we compare the left and right element for any given array, if the array is completely sorted, which is the
9:42:49
case in over here that the entire array has been completely sorted, there are no mismatching pairs, right? So because
9:42:55
this array is completely sorted if we compare the leftmost element and rightmost element or any element with
9:43:02
its left element uh basically we would find that the value at the left element
9:43:07
is always less than whatever value at the right element we have. Like if we compare these three variables and if we
9:43:14
compare the right variable to B over here basically again in this case the right is three and left is one. So we
9:43:19
can conclude that this whole portion is sorted. If we have the right variable located at this position uh basically we
9:43:27
can we have the value of left to be one and right to be five. Again left is less than one. So we can conclude that this
9:43:32
whole portion is actually sorted. So the lowest value that we can achieve in this whole portion between this left and
9:43:39
right is going to be whatever value that is located at the leftmost position. Now whenever we compare the left value and
9:43:46
right value and we determine that left is actually greater than right. If we find that left is actually greater than
9:43:53
right, we can determine that the minimum value exists somewhere between left and
9:43:58
right. We don't know that at what position minimum value exist. But the thing is we need to achieve to the
9:44:04
direction where we can actually find left is less than right because remember
9:44:09
over here currently the value of left is three and value of right is two. So in this case left is actually greater than
9:44:15
two. Whenever we have to find the minimum value, we will have to move in a direction where we will reach uh to a
9:44:21
conclusion where left is less than right. And in order to achieve that, what we are going to do is we are going to compare the value of the left to the
9:44:28
middle pointer that exist. And depending on the value of the middle pointer, we
9:44:33
would determine that the minimum value if does it exist on the left side of the
9:44:38
middle pointer or on the right side of the middle pointer. And depending on that we will update our value of left
9:44:44
pointer or right pointer. So let me show you with a broader example what I'm
9:44:49
trying to say. So I have drawn a big example over here and first let's uh denote assign our initial values of left
9:44:56
and right. Right? Uh so we have the values of left and right set up for us. Now we know that we need to reach to a
9:45:03
position where left is less than right. If that is the case then we will have some interesting results. Right? But
9:45:08
currently if we see the value of left is two and value of right is one. So left is actually greater than one. So now we
9:45:15
will have to move in some direction. So now what we are going to do is we are going to find the mid value. And also
9:45:20
remember we are going to have an answer variable that is going to store the lowest value we have been able to find so far. So currently the value of left
9:45:27
is two, value of right is one. Right? So we are not going to do anything in the answer yet. Now we are going to find the
9:45:33
middle pointer. So, so the current middle pointer is going to be at position number four. Why? Because left
9:45:39
position is 0, right position is 8. So, 0 + 8 is equal to 8 divided by 2. That
9:45:44
gives us the middle value. And middle value in this case is going to be the four. Right? So, the value that is
9:45:50
located at the fourth position is six. Now, we need to compare the values between left and mid. Left and mid if we
9:45:57
compare left is two and mid is six. So, two is less than six. Now remember whenever we identify that the left value
9:46:03
is less than whatever the value we compared we can dictate that every value
9:46:09
in between is actually greater than the value of the left. Which means that no
9:46:16
value amongst these values can be the answer or can be the minimum value
9:46:21
because uh remember we already know that on the right hand side the value is actually less than left and because of
9:46:28
that we will have to update our migration on the right side and also remember whenever we compare the value
9:46:35
of left value with the mid value whatever the lower value is we are going to store it. So currently the lowest
9:46:40
value we have been able to find is two. So we are going to store two as the answer. Right now we are going toh
9:46:46
switch our left pointer to go on the right side of the mid. So now let me clean this up a bit. So now this is
9:46:53
going to be our new left pointer and this is going to be our new right pointer. Again we are going to compare
9:46:58
the value of left and right. So left is actually greater than right. Right? So now we will have to find the midpointer.
9:47:03
Midpointer in this case is going to be left plus right divided by two. So current value of left is five. Right is
9:47:09
8. So 13 divided by two. If we put it floor value we will get the value of six. So six is going to be the middle
9:47:15
pointer in this case. So now we have the six to be the middle pointer. Now we are going to compare left with the middle
9:47:21
pointer. And now in this case left is actually less than middle pointer which means that answer cannot lie between
9:47:27
left and middle pointer and again we will have to update the value of the left pointer. Also for this leftmost
9:47:32
value we will compare that whether we need to update the answer or not. So answer currently we had was two and this
9:47:38
is seven. So we don't need to update the answer and we are good up until this point. Okay. Now again we determine that
9:47:43
this value is not the answer. Now our left pointer comes at this position. Our right pointer comes at this position.
9:47:50
Again we are going to compare the values of left and right. So currently left is actually less than right and that is the
9:47:56
ideal scenario that we found that left is le actually less than right which means that now left is at the correct
9:48:03
position to be the lowest position that it can be uh before it iterates or it
9:48:08
takes over right and now because of this one uh we are going to update uh we are
9:48:13
going to see that whether we need to update our answer or not. So current answer we had was two and because left was less than right we are going to
9:48:20
compare the left value with this answer value and uh the left value is actually zero. So we are going to update the answer to be zero and in this case this
9:48:27
is the correct answer that we are able to find and we are going to return that. Uh let's try to understand the same
9:48:34
thing with another example. So in this case left is over here right is over here. Currently uh left is actually
9:48:39
greater than right. So because of that we will have to find the middle value. So middle value is going to be this one. So now if we see currently the left is
9:48:48
actually greater than middle value as well which means we cannot determine that the left and middle portion is
9:48:55
actually completely sorted. We can only determine that the middle and right portion is completely sorted. So in this
9:49:00
case we are actually going to update the value of the right pointer and we are going to determine that these are all
9:49:05
the values that are not part of the answer. So we can just simply ignore them and we will not do anything for
9:49:11
these values. So now currently our right pointer comes over here. Now because of that we are again going to repeat the
9:49:17
same process and we will try to find the middle value. Middle value in this case is going to be eight. Right? So we are going to compare left with the middle
9:49:23
value. So left with the middle value if we compare left is actually less than the middle value. If that is the case we
9:49:28
can determine that no value over here is the middle minimum value. So we can simply ignore that. And now our left
9:49:34
value becomes this one. Our right value becomes this one. And now if we compare left is actually less than right. Left
9:49:40
is less than right. That is the ideal scenario that we were looking for which means that now left is at the correct
9:49:45
position where the value is actually minimum and in the answer we are going to denote the value to be zero and that
9:49:50
is going to be the answer we are going to return. Now if we see time complexity in this case the time complexity is
9:49:55
actually going to be big of log n because remember during any single iteration we actually removed the half
9:50:02
of the candidates that we are we were trying to search for and that is why we are actually using binary search in this
9:50:09
program to solve this problem and that is the logic we are going to use. Uh and now let's move on to the coding.
9:50:18
So first of all we are going to initialize three variables left right and answer. Now we are going to test for
9:50:24
an edge case that if the nums array only has one element basically we can return that as the answer. Okay if that is not
9:50:31
the case we are going to run our while loop that while left is less than or equal to right. First we are going to
9:50:37
check that if the current left and right position makes the array completely sorted or not. And that can only happen
9:50:42
if the value at number of left is actually less than whatever the value of
9:50:48
nums at right we have. And if that is the case we are going to see that whether we need to update our
9:50:54
answer or not. If that is not the case we will have to calculate the middle pointer. So first we are going to
9:50:59
initialize a value called mid and we are going to calculate the middle pointer. After calculating the midpointer we are
9:51:05
again going to check that whether we need to update our answer or not. Now we are going to see that which way on the
9:51:12
midp pointer do we need to take the jump. So if we if we find out that the
9:51:17
current value of left is actually less than or equal to mid value then we will have to update the value of left pointer
9:51:24
to the right side of the mid and if that is not the case which means we will have to update our right pointer. Basically
9:51:30
that's all we have to do for our binary search operation. After this loop ends, we can simply return whatever we have
9:51:36
stored in the answer. And now let's try to run this code. Okay, seems like our solution is working
9:51:42
as expected. Let's submit this code.
9:51:48
And our code is actually pretty fast compared to a lot of other solutions. And I will be actually posting the solution in the comments. So you can
9:51:54
check it out from there.
9:52:04
Today we are going to do search in a rotated sorted array. And if you see some of the companies where I want to get a job who have already asked this
9:52:10
question, there are companies like Amazon, Microsoft, Facebook, LinkedIn, Bloomberg, Apple, Tik Tok, Bite Dance,
9:52:15
Google, Goldman Sach, Uber and eBay. So that's why I'm paying my utmost attention. I hope you also enjoy the
9:52:21
video. This is a lead code medium problem and also very well-liked problem on lead
9:52:27
code. Basically, we are trying to search an element inside a rotated sorted array. Now, if you notice, this is very
9:52:34
similar to one of the previous videos we solved recently and you can check it out that over here. Now, uh we are basically
9:52:40
given an array called nums and we are also given a target value and we need to check that whether this target value
9:52:46
exists inside this nums array or not. If it does, we need to return the index of that target value. Now the special part
9:52:52
about this question is that the nums array we are given is actually a sorted array that has been rotated certain
9:52:59
times. So it sounds confusing at first that what does a rotated sorted array means. So you can either read this
9:53:06
definition that has been provided over here but uh let me make it a little bit clear for you. Uh basically a rotated
9:53:12
sorted array is that initially an array is a fully sorted array which is the case over here. You can see that all the
9:53:19
elements are sorted and they are all in ascending order. And the thing is whenever we rotate one time basically we
9:53:25
take the rightmost element we put it on the leftmost side and then we flip all the elements one side or one position to
9:53:32
the right and that is how we rotate and uh rotate a sorted array. So if we consider this to be the original array.
9:53:38
Suppose we rotate it one time. We will get a result that looks like this where this five that was originally on the
9:53:44
rightmost position came on the leftmost position and all the other subsequent value we jumped it one step on the right
9:53:50
side. If we rotate it two times again the four and five would come on the left side and all the values would be shifted
9:53:57
two times on the right side. If we rotate three times, basically all the values would uh be rotated three times
9:54:03
and we would get an array that looks like this. So the idea is we are given a
9:54:08
form of a rotated sorted array. The thing is we don't know that how many times it has been rotated or what not.
9:54:14
We are also given some target element and we need to see that whether this target element exist inside this array
9:54:20
or not. So suppose uh this is the array we are given as the input and we are given target is equal to uh three. If
9:54:26
that is the case then in this case three exists inside this array and its index value is zero. So we need to return zero
9:54:34
as the answer and this is what is being asked for this problem. So now let's see that what are going to be couple of
9:54:39
different approaches to solve this problem. The first approach we have is a brute force approach. In the brute force
9:54:44
approach what you can do is suppose this is the array we are given and we are given the target value to be zero. Well,
9:54:50
if we see uh what we simply do is we start iterating over this array uh one by one and every single time we iterate
9:54:57
until we find the value that exists. If the target value exists inside this array, whatever its index position is,
9:55:04
which is three in this case, we return that as the answer. And if we somehow reach to the end of this array and we do
9:55:10
not find this target value, we simply return that okay, the target does not exist. Right? The thing is this solution
9:55:16
is not the most optimal solution. Why? because the time complexity for this solution is going to be big of n.
9:55:22
Meanwhile, if we read the problem statement, we are explicitly told that we need to complete this in big of login
9:55:29
time complexity. And this big go of n is just just not good enough.
9:55:36
Okay, before we come up with the optimal solution, first let's understand a couple of concepts regarding the sorted arrays. Right? For the sorted arrays, uh
9:55:44
if we compare any left element with any right element, uh if we end at any point
9:55:49
identify that left is actually less than right and we know that this given array is a sorted array, right? And this left
9:55:55
is actually less than uh right. So if that is the case, all the elements between this left and right will be
9:56:02
sorted in ascending order. That is one of the properties of a sorted array. We already know that. Now uh the tricky
9:56:10
part we have is that the array we are given is actually rotated. So the thing is we will have to take care of this
9:56:15
rotated part as well and we don't know that how many times it has been rotated. So suppose we are given an array like
9:56:21
this. This has been rotated few times. Right now whenever we compare the left
9:56:27
element with the right element initially uh we can clearly see in this case that left is actually three and right is
9:56:33
actually two which means left is actually greater than right. Uh and remember we already know that when left
9:56:38
is less than right we already know that all the elements in between they are actually sorted and if we are trying to
9:56:45
find some target value that falls between this left value and this right value we can immediately find that
9:56:51
target value. Suppose we are given the target value to be three. We know that left value is zero and right value is
9:56:57
five. So because of that this target value has to be somewhere between this 0 and five because it it can only exist
9:57:05
between 0 and five because this portion is sorted. Three cannot be outside of the scope. The thing is we cannot say
9:57:12
that for certain in this case because over here currently if you see left is actually greater than right which means
9:57:18
we can determine one thing that this whole portion is not sorted. But the thing is we already know that a chunk of
9:57:25
this portion is sorted which is this that 3 4 5 this is sorted in ascending order. Again same way this 012 that is
9:57:33
also sorted in ascending order. Why? Because this was a rotated array. Right? So the thing is what now we are going to
9:57:40
do is we are trying to find some target value. Right? So our aim is that suppose we are given the target value to be
9:57:46
four. Right? Now we are trying to find the value four. The thing is for this rotated array the idea we are going to
9:57:53
use is that when we determine that left is actually greater than right which means that this whole portion is not
9:57:59
sorted right that is the key part this whole portion is not sorted but some chunk of this portion has to be sorted
9:58:06
and that we can determine by defining some middle value. So in this case suppose we put down a middle value. So
9:58:13
suppose we have a middle value that is zero. Right? Now with this zero what we are going to do is we are actually going
9:58:19
to compare this left with this middle value. If we compare this left with this middle value left value is equal to 3
9:58:24
and middle value is equal to zero. So if that is the case left is actually greater than middle value. So since that
9:58:30
is the case we are we won't be able to do much over here. And uh basically what
9:58:35
we will do is now again we are going to compare this middle value with this right value. So currently middle value
9:58:41
is actually zero. uh the right value is actually two. So middle value is actually less than right. Which means
9:58:47
because this was the rotated array, we can determine that all the values between this middle value and this right
9:58:53
value is actually completely sorted. This is the important property that we
9:58:58
have to define that this whole portion is completely sorted because of that. Now we will see okay our target value is
9:59:05
actually four. Uh the current middle value is zero. Current right value is equal to two. which means four does not
9:59:11
fall between 0 and two. Because it does not fall between 0 and two, we can concretely say that four cannot be part
9:59:18
of this particular chain. So immediately we can ignore all of these cases. And now what we'll do is we will shift our
9:59:25
right pointer to one step before mid. Why? Because we were certainly able to
9:59:31
say that this sorted property of this rotated sorted array help us determine
9:59:36
that four is not part of this one. All the elements between these portions were between 0 and two. Now we are going to
9:59:43
move our right pointer over here. So let me clean this up a bit. So now currently our left pointer is here. Right pointer
9:59:49
is here. Right? Now if we see left is equal to three. Right is equal to five. If that is the case, left is actually
9:59:55
less than right. And this is what the golden thing we wanted. Now we can clearly determine that this whole
10:00:00
portion 3 4 5 that is completely sorted. Because this is completely sorted all we
10:00:05
will have to do is just use binary search. uh in order to find the target value. So what we are going to do is we
10:00:11
are going to compare uh the middle value. So middle value in this case is four. Four is actually exactly the
10:00:17
target value we are looking for. So we will return the index position of four which is one in this case as the answer.
10:00:22
And the answer over here is going to be the one that we are going to return. Now after explaining this whole thing, let
10:00:28
me quickly go over one of the examples to see that how we will solve optimal solution using binary search.
10:00:36
Okay. So now as mentioned we are actually going to do the binary search operation on this rotated sorted array
10:00:42
right and the target we are trying to find is the value number zero now now we are going to use our two pointers so
10:00:48
first pointer we have is left that is located at this position number three and right pointer is located pos this position number two in this case
10:00:54
currently left is actually greater than right which is not what we want. So now we will have to determine that which
10:01:00
portion of the array sorted and based on that where this target value could lie. So we are going to compare with with the
10:01:07
middle value. So in this case the middle value is going to be seven right. So now we have this value number seven that is
10:01:13
located as the middle value. Okay. Now for this middle value we are going to compare it with left and right value. So
10:01:18
currently if you see left is actually less than middle value. And this is what we wanted. The moment we identify left
10:01:25
is actually less than middle value. We can clearly determine that this whole portion is completely sorted. Okay. Now
10:01:31
we will compare the target value we are looking for with the values of left and mid. So if we see the target value is
10:01:37
actually outside the scope of this left and mid which means that target value cannot exist between these places
10:01:45
immediately we can determine that. So we will ignore all of these cases and now we will have to update our left pointer
10:01:51
to go on the right side of the middle pointer. So we will do that. So now we will have our left new left value the
10:01:57
located at this position and the new right value located at this position. Now we are again trying to find the
10:02:03
value zero. Okay. Now immediately over here we can see that left by itself is actually zero. So that makes our life
10:02:10
much more easier and we can simply return the index value of this left to be five as the answer. And in this case
10:02:16
we are going to return answer as the five. And basically all we are doing is we are actually using the middle value
10:02:23
to determine that which portion of the array is sorted depending on that and based on the target value we decide that
10:02:30
which way we will have to make the jump and then we get our desired answer. If we see time complexity in this case the
10:02:35
time complexity is actually going to be big go of log n only. Why? Because uh remember in a single iteration we were
10:02:42
able to get rid of all of these elements immediately which means every single iteration we are doing like half uh we
10:02:49
are getting rid of half of the elements. So so that is why the time complexity is login and that is what we wanted. If we
10:02:54
see space complexity in this case the space complexity is actually going to be constant space because we are not using
10:03:00
any any additional data structure.
10:03:06
First of all, we are going to define couple of variables left and right. Okay. Now, we are going to initialize
10:03:11
our while loop that while left is less than or equal to right. And inside our loop, first of all, we are going to
10:03:16
calculate the midpointer. Now, we are going to check for the condition that if the given value of mid if that is equal
10:03:24
to target. If that is the case, we can simply return the index at mid. Okay. If that is not the case, now we will have
10:03:30
to first of all define that which portion of the midpointer is actually completely sorted. So first let's put
10:03:36
the condition that if the given value of left if that is less than or equal to whatever the value of mid is. If that is
10:03:44
the case, we can define that the values between left and mid is completely sorted. Right? So now all we will have
10:03:50
to do is we'll have to see that where target lies. Does it lies between left and mid value or it lies uh somewhere
10:03:56
else. So first we are going to see that what if the target lies outside of left
10:04:02
and mid value. If target lies outside basically we will have to update our left pointer to go mid + one and we will
10:04:10
continue with our journey. If that is not the case which means target lies between left and mid and if that is the
10:04:15
case we will have to update our right pointer to come between left and mid. So we will do right uh equal to mid minus
10:04:21
one. Okay. Now uh we take care of the scenario that the numbers of left is not
10:04:28
less than or equal to mid which means that the values between mid and uh right is actually sorted and if that is the
10:04:34
case again we are going to repeat the same process. First we are going to check that whether the target value is
10:04:40
outside the scope of mid value and right pointer. So if the value is outside of
10:04:45
the scope which means we will have to update our right pointer to search on the other portion of the array. So right
10:04:51
is going to become mid minus one. And if that is not the case which means that the values lies between uh mid and right
10:04:58
value. If that is the case we will update our left pointer to search between uh mid and right. So left would
10:05:04
become mid + one. And basically this uh loop should take care of the scenario
10:05:10
and we would be able to find our answer. And uh just for the sake of uh putting
10:05:15
something outside so we don't get a compilation error we are going to return minus one. But our answer would have
10:05:21
been returned by this. Now let's try to run this code. Okay, seems like our solution is working as expected. Let's
10:05:27
submit this code. And our code runs pretty efficiently compared to a lot of other solutions. And uh I will be
10:05:33
posting this solution in the comments. So you can check it out from there. Thank you.
10:05:43
Hello friends. Hope you are having a fantastic day today. So in this video we are going to solve an awesome lead code problem that has been asked in tons of
10:05:49
different companies. So without any delay let's get started. So the lead code problem we are going to solve today
10:05:55
is called sort list and you can see that this is a lead code medium problem and also a very well-like problem on lead
10:06:00
code. This has been asked at tons of companies and that's why you really need to pay attention. Now the problem
10:06:05
statement is really simple to understand that we are given the head of a link list and we need to return the entire
10:06:11
list in sorting ascending order. So if we see an example over here, we are only given the head of the list that is this
10:06:17
value number four and then rest of these values we need to iterate over using the link list and in the answer we need to
10:06:23
return a sorted link list that looks like this and you need to do this
10:06:28
problem. Now this is not specified over here but in the followup definitely the interviewer is going to ask you that
10:06:34
they are going to ask you to solve this problem in big of n log n time complexity and also big of one space
10:06:40
complexity. So this becomes a little bit tricky on in order to how to achieve both of these values in terms of time
10:06:47
and space complexity. So we will try to target these things and think that what is going to be our thinking like in
10:06:53
order to solve this problem in this much value this much time complexity and also without tuning using any extra space.
10:07:00
Now logically for let's assume that instead of this being a link list let's
10:07:05
assume that we are given a simple array and this is an unsorted array that we need to sort and we need to sort this in
10:07:12
n login time. How would we solve that? Suppose we are given the values like 2 4 7 1 and 3 something like this. Okay. So
10:07:20
this uh if we have to s sort this unsorted array there are actually bunch of different methods that solve this
10:07:26
problem in n log end time. We can apply like quick sort or we can apply merge sort. Both of them are going to be
10:07:31
really popular. We can also use like heap sort. But good thing about array is
10:07:37
that in order to access any single variable, we can do this in immediately
10:07:42
by the by knowing that what is the index value and then we can simply access this value. We don't have the same luxury to
10:07:48
do so in our link list. So that adds a bit of complexity and that's why many companies love asking this question.
10:07:55
Okay. Now let's try to do the merge sort for this given array. So the logical thing is we are going to first find the
10:08:01
middle pointer and break the array into two pieces. So first piece is going to be values 2 6 and four and second piece
10:08:09
is going to be value 1 and three. Now we will check that are they sorted. Now in
10:08:14
this case this array is already sorted. So we don't need to do anything further. This is a good candidate for us. But now
10:08:21
for this portion this is not sorted. So we are going to again repeat the same process. So once again if we break this
10:08:27
down into two pieces we will have one piece with value two and second piece with value 6 and four once again. So
10:08:34
currently we only have one value. So this is already sorted. We can't do anything much with this this 6 four. Is
10:08:39
it sorted? No it's not sorted. So if it's not sorted what we will try to do is we will try to sort this. But since
10:08:44
there are only two elements if we break them apart it's going to be one element each. That is going to be six and four.
10:08:51
And then we can simply swap these values and it would be very simple to sort this one. So after completing this operation
10:08:58
what we will be left with is we will be left with a value like two and then this
10:09:03
is going to be four and six. So now currently this portion is sorted. This portion is also sorted and this portion
10:09:09
is also sorted. So now we have three different arrays that we are trying to sort and the this is going to be very
10:09:17
simple to do. So what we will do is first we will take the these two arrays 2 and 4 6. So first we will compare the
10:09:23
very first element with the very first element and that's the only thing we need to do and that this operation can
10:09:28
be done in log and time because we already know that both of these are sorted. So whichever value is smaller is
10:09:35
always going to append first. So in this case since the value number two is smaller. So we will be left with a piece
10:09:41
2 4 and six as one piece and second piece is already 1 and three. So once again now we are going to compare these
10:09:47
two values. And we can see that this value number one has to go first. So we are going to put this value number one
10:09:53
over here. Then once again we are going to compare this value number two with value number three. So since two is
10:09:58
smaller so once again we are going to put two over here. Next we are going to compare this value number four with value number three. So since value
10:10:04
number three is smaller so we are going to put it before. And then for whatever the rest of the values are remaining
10:10:10
since this array is already completed done we can simply append all the values that are remaining as it is. So we are
10:10:17
going to add values four and six as it is. This is how merge sort typically works in an array and for that we
10:10:22
actually have to use extra space because we need to store the array and do all of these manipulations. Now the target is
10:10:29
we will try to replicate the same thing. The good thing about link list is that we don't have to worry about this extra
10:10:34
and space because we are working with link list. So we can actually use pointers to just point to the any
10:10:40
particular value that we are trying to do and we can just manipulate the nodes in the easiest manner. Now let's try to
10:10:46
see that what the solution is going to look like. So number one thing is that in the link list we are only aware about
10:10:52
the very first element. We don't know that what rest of the elements looks like and we have no no way for
10:10:58
verifying. So let's assume that the values currently given are like four 3 1
10:11:03
2 and five something like this uh six. Okay. Now we what we need to do is in
10:11:08
order to apply the merge sort first we will need to find the midpointer and we don't know how many elements are
10:11:13
currently in the link list. We only know the head element. So we know that if we have to find the midpointer all we need
10:11:20
to do is use fast and slow pointer method. And by doing this we would be able to find the midpointer quite
10:11:25
easily. For those who don't know how fast and slow pointer works is that we are going to have two pointers. Fast and
10:11:32
slow pointer start at the very beginning of the link list. Fast pointer is going to jump two hops and slow pointer is
10:11:39
only going to jump one hop every single iteration. So the moment we encounter that either fast pointer is at the null
10:11:46
location or fast. Next is the null location. Then we have reached to the last node for the fast pointer. And the
10:11:52
moment fast pointer reaches to the last node, whatever the position of uh this slow node is is going to be the
10:11:58
midpointer. So this is how we would be able to identify the midpointer. Now let's try to apply the same logic. So
10:12:04
for this one we are going to have two halves. First half is going to be 531 and second half is going to be 2 and 6.
10:12:10
Now 2 and six is already sorted. So we don't have to do much. But for this half once again we are going to find the
10:12:16
midpointer. So one half is going to be five and second half is going to be 3 and 1. And once again the this is this
10:12:22
half is not sorted. So once again we will sort this one 1 3 and then we will have 5 1 3 as 1/2. Once again these two
10:12:30
are not sorted and again these this is not array this these are linkless pointers. So once again recursively we
10:12:36
are going to repeat the same process and we will have 1 135 as the sorted arrays and then we will have another sorted
10:12:43
pair sorry sorted link list and another pair s 2 and six as the sorted link list. We will merge these two together
10:12:49
and we will find the values 1 2 3 5 and six as the final sorted link list and we
10:12:54
can do this in place using the pointers. So when we see that in the code we should be able to find or understand how
10:13:00
it works. So this is the whole approach. What we are going to do is for the link list we are going to use the merge sort
10:13:06
approach and in order to find the midpointer we are going to use the fast and slow pointer method. So you see in
10:13:13
this problem we are applying multiple concepts that are really important for
10:13:18
many different things and that's why this problem has been really popular in many different companies. Time and space
10:13:24
complexity we already know time complexity is going to be bigo of n log n and in terms of space complexity it's
10:13:30
going to be bigo of one because we are not using any additional space we are actually going to manipulate the pointers and the whole thing because
10:13:37
it's a same operation being done repeatedly it's a recursive approach and we can just solve this problem using
10:13:43
recursion. So now let's see the code for this. So if you see the solution first what we are going to do is we are going
10:13:48
to have our sort list method that we are going to recursively call for the different link list head. So first we
10:13:54
are going to have our terminating or base case that if the current given head is equal to null we return head. If head
10:14:00
dot next is equal to null then also we return head. Next we will have to find the midpinter. In order to do that we
10:14:06
are actually going to use an extra helper method called get mid. So first let's see the get mid method where this
10:14:12
is very simple. We are just simply using two pointers fast and slow pointer in
10:14:17
order to find the midpointer and the moment we get the mid value we simply return the mid value. So we have the mid
10:14:23
value over here. Then we also have the left node that is going to be the start node or the very first node that we are
10:14:29
given in the input for this sort list method and the rightmost node that is going to be the midpointer node or the
10:14:34
second half and then we simply need to apply our merge sort method. So we are going to call another helper method
10:14:41
called merge. And in this method we are going to have first of all couple of nodes dummy and tail node in order to
10:14:48
keep track of different pointers. Then we are going to simply check that while list one and list two are not null. We
10:14:54
are going to compare the values. If we find out that the values are not correct, we are simply going to swap the
10:14:59
values and then we are going to keep on iterating till we reach to the next element or the very last element and
10:15:06
that's it. So this is how we are going to do our merge sort operation and this is the whole code. Let's try to run the
10:15:12
code. Okay, seems like our solution is working as expected. Let's submit this code.
10:15:17
And our code runs very fast compared to lot of other solutions and it is also very efficient in terms of memory usage.
10:15:24
So once again I will be posting this uh code solution into our GitHub repository and link to that GitHub repository is in
10:15:31
the description.
10:15:39
Hello friends, hope you are having a fantastic day today. So in this video we are going to solve an amazing lead code
10:15:44
problem called largest number and this problem has been asked in companies like Amazon, Microsoft, Google, Facebook,
10:15:50
Bloomberg and bunch of others. So without any delay let's get started. So as you can see this is a very
10:15:56
well-liked lead code problem and also this is a lead code medium problem. Now let's try to understand that what the
10:16:02
problem statement is asking us to solve. Basically we are given a non- negative inteious nums array and we are being
10:16:09
told that we need to arrange this in such a manner that we get the largest number from combining all the numbers
10:16:16
that are currently present inside the given array. So let's try to understand this with couple of examples. If we see
10:16:21
this first example, we are given an array with two values 1 0 and two. So if
10:16:26
we combine these two numbers what is the largest number possible number that we can get. So in this case we cannot break
10:16:33
apart this existing number. So 1 0 has to remain 1 0 in all the cases but we
10:16:38
have the option to select from 2 1 0 or 1 2. So because currently we only have
10:16:44
two values. So we only have two possibilities and in this case 21 is the largest number. So we need to return 21
10:16:50
as as the answer. Let's try to understand the same problem with few more examples. So suppose we are given
10:16:55
the values like 3 5 and 10. If this is the value given to us, what is the
10:17:00
largest number we can make out of this? So one option is we can make a value 3 5 1 0. Second option is we make a value
10:17:08
like 5 3 1 0. Next we can make a value of 5 1 3 something like this. But in
10:17:14
either cases amongst all the possible values this is going to be the largest value we should be able to make. So in
10:17:20
this case we need to return this as the answer. So I hope my explanation makes sense to you and you can understand that
10:17:26
what we are trying to return. Now if we see the problem statement we are given couple of other things to make our lives
10:17:33
easy. Number one they are saying that uh the result could be very large numbers.
10:17:38
So we need to rather than returning integer values we can simply return string as the answer. And all we are
10:17:45
doing in this problem is that we are actually treating these values as string
10:17:50
values. So string one and string two. And then we are seeing that how can we concate string one plus string two in
10:17:57
such a manner that we get the largest number. So we have two options because we currently only have two values string
10:18:03
1 and string two in this case. So either we can concate string 1 plus string 2 which would result in the value 1 02
10:18:12
which is this value combining these two numbers or second option is we concate string 2 plus string 1 and in this case
10:18:19
the answer we get is 2 1 0. So because 2110 is larger than 102, we are going to
10:18:25
return 2110 as the answer. Now this is a very clear hint on how we are going to
10:18:30
solve this problem. Basically the idea is that we could have been given bunch
10:18:36
of different values inside the given array and somehow we need to sort this
10:18:41
array in such a manner where the very first element is the largest value and
10:18:48
we are not talking about largest in terms of like pure numerical value but
10:18:53
the largest first value and this we can only determine compared to rest of the
10:18:58
other values and I know what I just said might have gone over your head. So let me give you uh try to give you a simple
10:19:05
explanation. Okay, let's just go back to our example of values 3, 5 and 10. Now
10:19:11
in this case we know that that the answer is going to be 5 3 1 0 and this has to be the largest number. But how
10:19:18
can we come up with this largest number and if we have to make this number uh what should the sorted array should look
10:19:24
like? The so the sorted array should be that very first value should be value number five. Next value should be value
10:19:30
number three and the last value has to be value number 10. Now if we just take the example that in this given input
10:19:38
array we are simply trying to make the largest value as the numerical sorting
10:19:43
order and then present that largest value as the sorted array then it would not work because if you see in this case
10:19:49
if we just have to sort all of these values based on their value preposition we would get a value like this 10 5 and
10:19:56
three. But in this case if we combine these letters in this sequence we would
10:20:01
get value 1053. So 1053 is clearly a smaller value compared to value 53 1 0
10:20:08
which is what we need to return. So what I'm suggesting is that whenever we start
10:20:13
sorting the array the logic we are going to use is that let's assume that we are we want to compare two numbers. So
10:20:20
currently the two numbers we are comparing is five and 10. Okay these two number. So rather so what are the
10:20:27
options we can have? Number one option for this array is that either five can come before value number 10 or 10 can
10:20:34
come before value number five. But in either case how we are going to determine we are going to determine by
10:20:40
combining these two values as if they are string concat string concatenation
10:20:46
and let's see that what approach we come up with. Okay. So now currently the premise is we only have two values 5 10
10:20:53
and another value is 10 5. So which sequence should be the correct sequence. So we are going to combine the values.
10:21:00
So if we combine this we get the value 5 1 0. If we combine this we get the value 105. And in this case 5 1 0 is clearly
10:21:08
greater. So when we are sorting our array to generate the largest number
10:21:13
five has to come before value number 10 somewhere. And this is the logic we are going to apply to solve this problem. So
10:21:20
I'm going to show you two examples of solving this with like a simple problem and a complex problem and that would
10:21:28
enable your mind to come up with the answer. And if you are having any issues or if you're not able to comprehend what
10:21:33
I'm suggesting all I say is that you apply this logic to sort the array and
10:21:38
you should be able to find the answer. So this next portion is for anyone who got confused. So that then just look at
10:21:45
the example. But if you already understood what I'm trying to say then you can basically conclude this video.
10:21:50
So now let me just explain uh my theory with couple of examples. So number one example is once again the let me take
10:21:58
three values. Okay. So 7 uh 2 and 9. Okay. This uh these are the three
10:22:04
numbers we are taking and we know the biggest number we would be able to make is going to be 9 uh 2 972. Okay. Let me
10:22:12
take a little bit more complicated value because this is very simple. So instead of two, we are going to take the value
10:22:18
20. Okay. And now the largest value we should be able to make is 9720. But let's see the approach. So first what we
10:22:25
are going to do is we are going to apply the same logic that when we are comparing two values a and b, we are
10:22:30
going to compare a plus b and we are going to compare b plus a. And this is not plus as in like mathematical plus
10:22:36
but you can consider this plus as a concatenation of two numbers. Okay. So now currently the two values we have is
10:22:43
7 and 20. We are trying to compare. So what are the two options? Number one option is that we have 720. Second
10:22:50
option is 207 because this 2 0 has to remain uh together. So amongst these two
10:22:57
value we can clearly see that 7 is greater value and 20 is lesser value. So
10:23:02
after comparing these two element we can conclude that seven has to remain first
10:23:07
and 20 has to remain second. But now we still have to make sure that where we are going to put this value number 9. So
10:23:13
once again let's compare this value number 9 with this value number 20. So if we compare 9 and 20, we have one
10:23:20
option is 920 and second option is 209. So clearly 920 is greater. Which means 9
10:23:25
has to come before value number 20. So let me make this adjustment. And currently 9 has to come before value
10:23:32
number 20. But is 9 at the correct place? No. Because we still have to check with value number seven. So once
10:23:38
again we are going to compare the value 79 and 97. Once again 97 is greater
10:23:43
which means 9 has to come before value number 7. So let us also adjust the value of this 9. So now currently this 9
10:23:51
is very first element and this seven is the second element. Now since we ran out of elements over here which means we
10:23:57
can't do anything in this case. So this has to be the correct sequence of numbers that are sorted in ascending
10:24:03
adder order such a way that combining these is going to result the largest number possible. So let's combine these
10:24:10
values and we the answer is going to be 9 720 and this is what we need to return. Let me give you just one more
10:24:16
example really quickly just for the explanation sake and let's take some
10:24:21
larger example. So the values are 3 50 20 and 9 and 1. Okay, this is the
10:24:28
number. So let's start comparing. So first we compare this value 3 and 50. So one option is 350 and second option is
10:24:34
503. Which means definitely 50 has to come before value number three. So okay
10:24:39
now currently we are comparing this value number uh three with value number
10:24:45
20. So once again if you do that 203 versus 302 or sorry 320. So once again
10:24:52
320 is going to be greater. So we are going to put three before value number
10:24:57
20. This is correct sequence. Now 20 compared to 9. So once again the one option is 209. Second option is 902. So
10:25:05
definitely 9 has to come before 20. And once again if we keep on repeating the same process with three once again 9 has
10:25:11
to come before three as well. And same way 9 has to come before 50. So the value is going to be 9 then 50 then 3
10:25:19
and then 20. Okay. And last value is 1. So 1. Okay. Okay, if we compare 20 with
10:25:26
one, the answer is going to be 2 0 1 and 1 uh 2 0. So 201 is greater. So value
10:25:32
has to be two uh has to be one. And if we combine all of these values, this is the correct sorted order. And I really
10:25:38
quickly glance over it because uh I just wanted to explain the how the method is going to work and the answer is going to
10:25:44
be 950 3201. And this is going to be the largest number we should be able to make
10:25:49
from given this input and this logic would work perfectly fine. Now for most
10:25:55
of the languages like Java, Python, C++ they already have a sorting meth uh
10:26:00
sorting method in order to sort the arrays and we can sort them in any order. So even for this one we should be
10:26:07
able to take or utilize this sorting method in order to generate the array and this sorting usually works in n log
10:26:14
n method where we we use comparator method to compare any two elements in order to sort them. What I showed you
10:26:21
over here was a very slow approach. This would work in big go of n² time but
10:26:26
since we already have a sorting method that is built in that runs in n login time we should be able to use that and
10:26:32
that is going to yield us very good result in terms of time complexity. If we see space complexity space complexity
10:26:38
is going to be big of n because many cases this sorting algorithm usually takes big of n space and that's these
10:26:45
are the uh time and space complexity. Now let's try to see the coding solution. So very first thing we are
10:26:50
going to do is create a new string array because we will have to convert all the numbers into the string and then we are
10:26:55
going to iterate over our given nums array into uh simple for loop fashion and convert all the values into the
10:27:02
string values. Once we have our string array, now all we need to do is use the pre-existing arrays dots sort method
10:27:09
where we are comparing two elements in such a manner that we are concinging the
10:27:14
strings a and b and we are comparing a + b and b + a and seeing that which value
10:27:20
is greater compared to the other value. Once this is done, the array should have been sorted. Now let's just take we are
10:27:27
just taking care of one of the edge cases where if the given value uh has the largest value or the very first
10:27:33
element as zero we can simply return zero. If that is not the case we will simply run a string builder operation
10:27:40
where we are going to uh concat all the values that are currently present inside our string array which we have already
10:27:46
sorted in ascending order in terms of completely larger values. And then we
10:27:51
can simply return the largest number that we have been able to build using our string builder method. So now let's
10:27:57
try to run this code. And seems like our solution is working as expected. Let's submit this code.
10:28:06
And our code runs very fast compared to lot of other solutions and it is also very efficient in terms of memory usage.
10:28:13
So I would be posting this solution into the GitHub repository that we have created. And uh if we see this GitHub
10:28:21
repository contains hundreds of different lead codes uh code solution questions and answers and I will be
10:28:28
posting there and the link to this GitHub repository is currently present inside the description of this video. So
10:28:34
I hope you uh like it you enjoy it and uh till then take care.
10:28:46
Hello friends, hope you are having a fantastic day today. So once again we are going to do an awesome lead code
10:28:51
problem that has been asked at tons of companies and it's actually a pretty fun question to solve. So without any delay
10:28:56
let's get started. The problem is called coco eating bananas. This one is a late
10:29:02
code medium problem and also a very well-like problem on lead code. Basically we are being told that Koko
10:29:08
loves to eat bananas. Now Koko is a very famous gorilla and we are given two items. We are given a piles array which
10:29:16
contains that every single element in in this array represents the number of bananas that that particular pile has
10:29:23
and we are told that there are guards who are typically protecting the bananas but they have gone out for 8 hours. So
10:29:30
we are given two these two items as an input. Now Koko decides to eat her
10:29:35
bananas per hour eating speed of K and each hour she chooses some pile of
10:29:41
banana and then she eats K bananas. So whatever the speed we decide she tries to eat that. If the pile has less than K
10:29:48
bananas then she eats all of them and will not eat any more bananas during
10:29:53
this hour. And the most important thing is we need to return minimum integer k such as she completes all the bananas
10:30:00
within each hour and we need to make sure that this k is the smallest element possible because koko likes to eat
10:30:07
slowly. So let's try to understand this problem with an example. So over here we are given piles. This represents that
10:30:13
pile one has 30 different bananas. Next one has 11 and next one has 23 and so on and so forth. And we are being told that
10:30:20
the guards have gone for 6 hours. Okay. So now we need to figure out that in
10:30:25
this 6 hours what should be the speed of banana eating for Koko in order to
10:30:31
complete every single banana in each of the pile and also at the same time make
10:30:37
sure that she tries to eat in the slowest speed possible. Now one important detail is that at any given
10:30:43
moment Koko can only eat bananas from only one of these piles. She cannot jump
10:30:49
around between the piles from hour to hour. So let's say that currently we have the speed of a banana eating at 50
10:30:56
per hour. Then let's assume that in the first hour she decides to eat 30 bananas
10:31:02
which means she still has time to eat 20 more bananas but she would not go to the
10:31:07
next pile to start eating them. She will only eat 30 and then wait for 1 hour and
10:31:12
during the next hour she will go to the next pile and once again start eating bananas. But once again she still has
10:31:18
room to eat 39 more bananas. But she would not move to the next element. Okay. So maximum hours we have is six.
10:31:26
That is number one thing. Now let's see that what are the some of the options that we can consider for for assumption.
10:31:33
We take the largest number in this pile that is 30. And we say that Koko eats 30
10:31:38
bananas per hour. So then in how many hours will she complete eating all the bananas? So during the first hour she
10:31:45
would complete this pile. Then during the second hour she would complete this pile and so on and so forth. In every
10:31:50
single hour she will complete each of the piles and then uh she would have still completed her banana eating in 5
10:31:58
hours. So less than six. But the thing is question is can we go smaller than 30? That is also a question. We need to
10:32:05
find the minimum number. So let's say that and we try the second smallest element that is 23 per hour. Then how
10:32:13
many hours will it take for Koko to complete all the all the bananas? So if we do 23 hours, so K is equal to 23.
10:32:22
Then logically in the first hour she will complete 23 bananas. So she would
10:32:27
still have seven more bananas left in this pile to complete. So it during the
10:32:32
second hour she will also complete seven more bananas. Then during the third hour
10:32:37
she will complete 11 bananas. Then during fourth hour she will complete 24. Then fifth, then fourth and then sixth
10:32:43
hour she would complete these 20 bananas. And then by the time of six hours she would have completed all all
10:32:50
the bananas in every single pile and her speed would be 23 which is significantly less than the previous speed that we
10:32:56
were considering that was 30. Let's try to consider one more speed. Okay, let's say that uh instead of 23 can we go
10:33:03
smaller than 23. So let's try 22. Okay. So if we try to do 22 then this pile
10:33:09
would take 2 hours. This pile would take 1 hour. This pile would once again take 2 hours. And then these two piles would
10:33:16
also take 1 1 hour. So if we do total sum of this, this actually becomes seven. So that is greater than six.
10:33:23
Which means speed 22 is no longer feasible for Koko to eat bananas. So
10:33:28
minimum speed she can use in order to complete all the bananas and at the slow
10:33:33
slowest speed possible would be 23. And this is what the problem is actually asking us to solve.
10:33:43
Well, brute force approach is actually quite simple because we know for sure that uh the maximum value has to be the
10:33:51
maximum value that is currently present inside the given piles because we are being told that the inputs are valid and
10:33:56
legitimate. Which means that if she eats the speed at the maximum number of
10:34:02
bananas that are present inside the all the piles, then by that limit she should
10:34:07
be able to complete every single one of them. But that is not going to be the ideal scenario. Maybe it might would
10:34:13
have it might have been ideal if instead of over here instead of this H being 8 we only had 4 hours to finish. Then we
10:34:20
have to eat at the speed of 11. But that is not the case. So what is the minimum
10:34:26
range? Okay, so maximum range that Koko needs to eat bananas is going to be the
10:34:31
maximum value. So 11. The minimum range can be value number one. Okay, that let's say that in this case we actually
10:34:38
have uh sum of all of these values. So we have 28 hours. If we have 28 hours, then if she eats one banana per hour,
10:34:46
then also she can complete this entire pile. But that is not that is also not the case. So we find our maximum and
10:34:52
minimum ranges. So logically what we can do is we can simply take every single
10:34:57
range and then try to go over to see that if that range satisfies the
10:35:02
property of uh completing the banana eating and then we can come up with the answer. So we already know the logic.
10:35:08
Let's say that with one we can complete it would take us 28 hours to eat all the
10:35:14
bananas but 28 is greater than 8 which means one would not work. So we try to do it with two. If we have to do it with
10:35:21
two once again it's going to take let's say 15. So it's going to take 15 hours but this is also greater than 8. So two
10:35:28
is also not going to work. So so on and so forth. If we repeat the same process, we would find the answer four in this
10:35:34
case uh that this is the number of banana she needs to eat in order to complete the entire pile. So logically
10:35:41
this solution works as expected. Okay, that is number one thing brute force approach. But the thing is the time
10:35:47
complexity in this case would be bigo of n where n is uh n is the number of the
10:35:53
sum of all the bananas that are currently present inside the combination of all the loops. But we will try to do
10:36:01
things slightly faster. So let's try to see that what would be the optimal approach in this case.
10:36:10
Now for this given example I have actually calculated the speeds from 1 to
10:36:16
11 uh for every single hour the banana eating speed and I have marked that at
10:36:22
that particular speed how many hours will it take for Coco to complete eating all the bananas. And the important thing
10:36:29
in this case is we need a value where we reach value number eight at the very
10:36:35
first time. The moment we hit very first time that is the minimum speed Koko
10:36:40
should eat bananas at in order to complete all the bananas within the given hours for which guards are away
10:36:47
for. So logically we can make one very important distinction over here that
10:36:52
with increase in the value of k we can see that the uh value of h reduces
10:36:59
significantly in a sorted and descending order which means we can see that there
10:37:06
is a descending property over here that is being maintained. Now the question is we need to find the minimum value. But
10:37:13
the lucky thing for us is that we actually can use the the benefit of this
10:37:18
property of uh this value being sorted to our advantage. What we can do is
10:37:24
instead of using the brute force approach where we were starting from k is equal to 1 and then just going in the
10:37:30
linear fashion for every single bananas until we hit value number eight. We can
10:37:35
actually use binary search in this case in order to complete this problem. Now let me show you that how doing binary
10:37:43
search would be the greatest things in sliced bread in this approach because we
10:37:48
we have our minimum range. We have our maximum range which means we can we know
10:37:53
for sure that our answer has to lie somewhere between this because any value above 11 will always yield us the result
10:38:00
S4. We can go even with a speed of 50 and still it is always going to give us
10:38:06
the result as four. Which means the important thing is that once we have our
10:38:12
left and right pointer or the minimum and maximum values so let's mark them. So currently we have our left pointer
10:38:19
and we have our right pointer located at these two positions. Our aim is to find the minimum value in this k that
10:38:26
represents that h becomes 8 for the first time. And the logic is quite
10:38:31
simple. We we take L and R. We we try to find the midpointer. So we check that
10:38:38
for this particular one, what is going to be the midpointer? I think midpointer is going to be this value number six. So
10:38:43
for value number six, what is the total number of hours that we can use in order
10:38:49
to generate the answer? So we can see that this value is six. Six is actually less than value number eight, which
10:38:54
means this is one of the legitimate scenarios. But the question is is this the minimum value we can reach eight?
10:39:01
No, because we will need to find the value that equals to 8 at the very first moment. So then once again now we are
10:39:08
going to bring our right pointer one step before this one and we will have a right pointer on this location. Once
10:39:14
again we will try to do the mid mid operation. So now if we do the mid operation we realize that midpointer is
10:39:21
actually this one. So this is actually ours is equal to 10 which is greater than the target hour we had that was
10:39:28
value number eight which means we will have to increase the speed in this case. So since we have to increase the speed
10:39:34
we will have to update our left pointer. So we will update our left pointer to come over here. Now we have two values
10:39:40
left and right located adjacent to each other but still we will try to find the midpointer in this case. So in this case
10:39:46
if we try to uh take the advantage of the ceiling value we will find midpointer to be value number four.
10:39:52
Okay. And then uh this refers to L number eight which means this is exactly what we are trying to find. But the
10:39:57
thing is we are not sure if this is the smallest value or not. So for that what we can do is we can simply check one
10:40:04
value adjacent to it before it to see that if that value is actually greater
10:40:09
than or less than value number eight. If that is less than 8 which means we might have missed some values where eight
10:40:15
started forming which we did not. So in this case we know for sure that this has to be the smallest value of banana
10:40:23
eating speed that we can use in order to finish all the bananas within the given 8 hours. Now we all know that how to
10:40:30
calculate hours for any single pile. For that we simply have to iterate over the given array. see that what are all the
10:40:36
bananas are and at that speed how many bananas can be completed in that particular aisle. So that for that
10:40:44
calculation we can simply use a helper method to complete that and basically this would yield us the complete result
10:40:51
in order for us to find the answer. So now this is a beautiful solution for an
10:40:56
awesome problem and uh it contains one of our uh very near and dear uh species.
10:41:03
So that's that's always pretty good. So now let's try to find the time and space complexity. In this case, time complexity is quite simple. It's going
10:41:10
to be big of log n in order to complete the binary search. And if we will also
10:41:16
have to do some computation in order to find that how much time it takes to eat all the bananas. So let's say that that
10:41:23
becomes big of h. But the thing is that calculation is always going to be finite. Why finite? because we uh we
10:41:31
know that the number of given input size n is going to be finite and we will have to iterate over all the elements in
10:41:37
order to calculate that. So that operation in itself is going to be big of n. So in this case uh you the total
10:41:44
time complexity is going to going to be big of n log n because for every single
10:41:50
pair that we can make up until this login time or the to till that optimal
10:41:56
period we will have to find that how many hours it takes to calculate the results which is going to be much faster
10:42:01
than our brute force approach because in brute in the brute force approach we anyways we had to do this big of n work
10:42:08
but we had to do it for every single possible value of k. So we were actually getting big of n square result and if we
10:42:14
see space complexity well in this case I just draw this additional uh data structure for your understanding but
10:42:21
actually apart from storing few variables here and there we don't have have to use any extra space. So this is
10:42:26
also going to be big of one fun. So this is a beautiful time and space complexity to solve this problem. Now let's see the
10:42:32
coding solution for this one. So here is the solution.
10:42:40
So first we so first we are going to initialize two variables left and right.
10:42:45
Now for the right pointer we will have to find the maximum value inside the inside our given piles. So we are going
10:42:51
to do that with a using a for loop. Then we are going to run our binary search logic where we are going to check that
10:42:58
while is while left is less than right. We are going to find a midpointer and then we are going to call our helper
10:43:04
method to check that whether we can finish finding uh the given piles using
10:43:11
the given midpointer or the speed that we have been able to find with the given
10:43:16
h hours in the input. Now let's understand the logic for the can finish helper method. First we are going to
10:43:22
mark that the initial hours are going to be zero and then we are going to compare that in order to complete this piles how
10:43:30
many hours it's going to take. So we are going to check that if the number of speed is going to be greater than any
10:43:36
particular pile then we can finish it in 1 hour. If not then we need to increase the hour. If the number of hours are
10:43:43
less than or equal to the given value h we can determine that that speed can actually finish all the bananas. Then we
10:43:50
need to check that whether the right pointer is equal to mid. If that is not the case, we need to find that left
10:43:55
pointer is going to be mid + one. And in the end, whichever is the left pointer has to be the answer. So this solution
10:44:02
would work as expected. And now let's try to run this code.
10:44:10
Okay, seems like our solution is working. Awesome. Let's submit this code.
10:44:16
And our code runs pretty fast compared to lot of other solutions in terms of time complexity. It is really good in
10:44:21
terms of space complexity as well. So once again the solution for this code is presented in our GitHub repository. So
10:44:27
you can check it out from there. Thank you.
10:44:35
Hello friends. Hope you're having a fantastic day today. So once again we are going to solve an awesome lead code problem. But now we are also going to
10:44:42
learn a very popular advanced data structure in this problem. So I'm going to pay my utmost attention. I hope you
10:44:48
also enjoy the video. So the lead code problem we are going to solve today is called timebased key value store. We can
10:44:54
see that this one is a medium problem and also a very well-like problem on lead code. The problem statement is
10:44:59
actually quite a long. Basically we need to implement a time map class but there
10:45:05
are a lot of conditions in order to implement this time map class. So we need to design a timebased key value
10:45:11
data store that can store multiple values of the same key but based on the
10:45:17
time stamp. So depending on what at what time stamp what key value we received we
10:45:22
need to store that and we also need to retrieve the same key value pair depending on the certain time stamp the
10:45:30
value that that we have been provided. Now number one we need to initialize the object for the time map uh data
10:45:37
structure that we are trying to create and we also have to set two methods. First one is a set method where we are
10:45:42
providing three values. First one is the key. Second one is the value associated with that key and third one is the
10:45:48
timestamp associated with both of these keys and values. Now next one is a get
10:45:54
method where we are providing the key with for which we wants to get the value
10:45:59
and we are also providing the associated timestamp. So by based on using the
10:46:05
combination of these two we should be able to find the value associated with this particular key. The other thing is
10:46:12
if say for an example for this time stamp we don't have the value associated with the key then we need to find the
10:46:19
closest value that was present at that particular time stamp and for some
10:46:24
reason we don't find any value for the key then we need to return an empty string. So let's try to understand this
10:46:30
with an example. Basically we need to create a data structure and that data structure needs to store three items.
10:46:38
First item is the key that is going to be the unique pointer. Second value is
10:46:43
the associated value with that key plus the time stamp. Now the the other thing
10:46:48
is that typically we usually see that keys tend to remain common in data structures like hashmap and uh other
10:46:55
like hashing based algorithms. But in this case we can have multiple keys with the same value but the only difference
10:47:02
would be time stamp. So in this case the value would not be truly unique because the entire value portion is actually
10:47:09
combination of value plus time stamp. So let's try to understand currently we have an empty data structure. Now let's
10:47:16
try to enter the values path as the key and the vas uh that is my last name as
10:47:23
the value and we are also providing the time stamp at one. So at time stamp one
10:47:29
we enter these values which means in our data structure we should have the key as P and we should have associated value as
10:47:36
V and the value this was located at value number one. Now let's say for some
10:47:42
reason during the time stamp number two once again I provide the value path we I
10:47:48
also provide the value as let's just say uh J and um that's it the time stamp is
10:47:53
two. Now once again I'm going to store the value P and this time the associated value is going to be J but this is
10:48:00
located at time stamp number two. Now once again I have another value path.
10:48:05
Once again the value is K and once again the time stamp is three. So once again I'm going to have another entry in my
10:48:12
data structure for path. The value associated is K and the time stamp is three. Now say that I do a get
10:48:19
operation. For the get operation, I provide the value as key path and I also
10:48:24
provide the time stamp to be two. So in this case, the answer I should be receiving back would be value number J
10:48:32
because J was the value stored for this path key at time stamp number two. So
10:48:37
this should return a J as the answer. Let's say once again I do another get operation. This time I provide the value
10:48:45
path as the key and as the time stamp I provide value number seven. Now you must be wondering that hey we don't have any
10:48:51
value stored at value number seven as part of the time stamp because we currently only have three timestamps
10:48:57
that is 1 2 and three and for each one we have a subsequent values stored inside our data structure. So in this
10:49:04
case the idea would be to find the closest value for this particular one.
10:49:10
So the the uh floor value associated with this time stamp which is going to
10:49:15
be value number three because three is the first value we can reach from time stamp number seven and for this the
10:49:22
value associated was K. So we are going to once again return K as the answer for this one. Now let's say that for some
10:49:29
reason I do a get operation for let's say John and I provide the time stamp to
10:49:35
be five. So once again I don't have any entry for John. So this should return us an empty string. Uh and once again I can
10:49:42
do a set operation. I can add value number John. I can add the uh associated
10:49:48
value as Cena. And I can associate the time stamp to be six. So now in this
10:49:54
case the value going once again we are going to have a new entry called John and associated value Cena. So this is
10:50:01
the whole idea of the type of data structure that we are trying to design. Now let's try to see some of the
10:50:08
possibilities with this type of data structure that we are trying to convey. Now think for a scenario that if we only
10:50:16
had to design a data structure where we are simply dealing with a key and its associated value. There is no such
10:50:23
concept of time stamp. Let's just say that if this is the case, how would the things things might behave? The idea
10:50:30
would be quite simple. We can simply implement a hashmap. Inside the hashmap, we typically store values based on the
10:50:36
key and its associated values. And we can store all of these values one by one
10:50:42
based on the distinct key values. And we can simply uh complete all the operations in big go one time like
10:50:48
insertion, deletion, searching and whatnot. So this is a very easy way for
10:50:54
for us to store the values. Now in the same example what I'm suggesting is that
10:51:00
instead over here as part of the key once again we use hashmap but now for
10:51:06
this uh hashmap in part of the value rather than storing just the value as it
10:51:13
is we actually store an instance to another hashing solution and this
10:51:20
hashing solution should have another block like this that contains two values. First one is the value and
10:51:27
second one is the time stamp and based on this it should be able to store all the values that we need and we should be
10:51:34
able to find particular time stamp on that particular value and we can we can return all of those values and this is
10:51:42
actually the whole solution that we need to build up. The idea would be that we
10:51:47
are actually going to use the combination of hashmap to store the standard key
10:51:54
and its associated association to store another hashing hashing solution. And we
10:52:00
all can understand that why are we using hashmap to do that because hashmap does all the operations in big of one time
10:52:06
plus it's a hashing solution. If we identify at any point that there is uh an existing key, we can do that
10:52:12
operation in big of one time and also for the associate value we can actually directly have multiple values. But in
10:52:20
this case, we we don't need multiple values. We need a separate hashing solution. For that, I'm suggesting to
10:52:25
use a tree map. Why are we using a tree map? Well, first before going down
10:52:32
deeper into understanding that why are we using tree map, first let's understand that what a tree map is. So
10:52:38
tree map is actually built on top of a hashmap. That is number one thing it so
10:52:44
it tree map contains a very similar property where once again we can have a key value pair operations and we can
10:52:50
store bunch of different values. But the other thing is that tree map is actually
10:52:55
contains a property of a binary search or logarithmic time uh valuation storing
10:53:03
property. So how does it do that? Well, actually tree map is built based on red
10:53:09
black trees. Now let me know in the comments if you want to understand more that how does red black trees work
10:53:16
because in itself it's a very interesting topic to learn and it has many practical use practical use cases
10:53:22
and applications. Basically what red black trees allows us to do is that
10:53:28
instead of normally having a single hashmap where we are only dealing with simple key value in tree map we are
10:53:34
dealing with three values. We are dealing with a key. We are also dealing with a value. Plus, we are dealing with
10:53:40
an extra bit that stores the value of a color. And storing the value of this color actually allows us to identify at
10:53:48
any given moment. Whenever there is a conflict, this color has to be the difference maker which we can actually
10:53:55
use to find that what was the value associated at that particular time. So I
10:54:00
know it sounds confusing but it's actually very simple to understand because this property actually allows us
10:54:07
to store all of these values in a binary search manner and we all know that how
10:54:13
does a binary search work that typically we can go in any particular direction to
10:54:18
find the value we want and in this case the particular direction or the color would be dependent based on the time
10:54:25
stamp that we fetch the value at and that's it. This is the whole solution.
10:54:31
So let's try to run the solution with some example and then you would it would make more sense to you. We know that we
10:54:38
need to we need two items. We need our hashmap and we need our tree map. Now
10:54:43
the thing is for hashmap we are simply going to have key as part of the key that we are coming in as an input. As
10:54:50
part of its value we are actually going to store the subsequent tree map instance. So as we the tree map instance
10:54:58
would be unique for every single value and inside the tree map instance the
10:55:04
unique part is that we need two items one is key and second one is value. So as part of the key we are going to store
10:55:10
the time stamp and as part of the value we are going to store the associate value that we are given in the input. So
10:55:16
let's say that first input we have is key is path. So I'm just marking it as p. Uh associate value is vas. So once
10:55:24
again I'm just marking it as as V and the time stamp is value number one. So in this case currently we don't have any
10:55:30
entry. So we are going to create a new value P associated with path we are
10:55:36
going to have associated tree map that we have to consider. So this instance of
10:55:41
the tree map would be marked over here. Okay. So let's just uh say that this is the instance of tree map. Okay. And
10:55:48
inside the instance of the tree map we are going to store one as the value that
10:55:54
we have or as the keep because this is the time stamp and its associate value we are going to store value number vasp.
10:56:01
Now let's say that once again we received the value for the same key path and now this time the value is h and the
10:56:08
time stamp is three. So once again for this same path we already have the entry. So we already have this one. Now
10:56:15
we all we need to update inside the existing uh time stamp. So for this one tree map once again we are going to
10:56:21
another entry three and now this time the value is going to be h. So we store the value h over here. Once again we get
10:56:27
another entry path. Once again the value is let's say x and the time stamp is
10:56:33
five. So once again we we only have one entry inside our hashmap. We have the time stamp to be five and we have the
10:56:40
value x associated with that. Now let's say we receive another value John. Now
10:56:46
the value is Cena and the time stamp is seven. So we don't have entry over here. So we are going to create a new entry
10:56:52
John. Now we also have to create a new instance of the uh tree map. So we are also going to do that for the John. And
10:56:59
over here we are going to have our time stamp and value. Time stamp in this case is going to be seven and value
10:57:05
associated is going to be Cena. And this is how the whole solution would work. Now let's say at any given moment I want
10:57:12
to do a get operation. If I try to do get path at time stamp number seven. So
10:57:18
currently I will go over here because this is the key for path. Now once again
10:57:23
this would take me to this tree map. For this tree map I don't have value number seven but I have something closest. Now
10:57:30
the thing is all of these keys inside the tree map are actually stored inside some sort of a binary search tree or a
10:57:37
red black tree which means finding that where does value number seven exist should only take us logarithmic end time
10:57:45
and not actually end time in a normal hashmap it would take. So in this case
10:57:50
we can find out that seven is not present but seven is not present. We can also find out that what is the largest
10:57:56
value present that is value number five. So associated value is x. So for this operation we can simply return x as the
10:58:02
answer that hey this is the value associated uh closest to this particular time stamp and same way if we get
10:58:08
another entry let's say get uh John and for John we also get time stamp to be
10:58:14
nine so once again we can just go to John we go to it's a subsequent tree map
10:58:20
for this tree map the largest entry is seven the associate value is cena so we can return Cena as the answer and that's
10:58:26
it this is how we can use the combination of tree map and hashmap to
10:58:32
store all the values. Now let's try to calculate the time and space complexity. In this case the time complexity is
10:58:37
going to be big of log n for the set operation and also big of log n for the
10:58:44
get operation. And why login? Because tree map operates in logarithmic end
10:58:49
time complexity because it's a red black tree and I'm also repeating because this is a very popular concept. So that's why
10:58:55
space complexity. So space complexity is actually unique to calculate. It's going to be big of K. So K presents number of
10:59:03
unique keys multiplied by number of total values that we are being given. So K multiply by N because we only need one
10:59:10
hashmap to store all the unique keys. But per unique key we also have to
10:59:15
create multiple tree maps. So that's why space complexity is little bit higher but time complexity is extremely fast.
10:59:22
And this solution actually is being used in many applications such as cache or uh
10:59:28
some sort of like high time functioning time based data structure that you are trying to trying to design. So that's
10:59:34
why this question remains a good good amount of popular. Okay.
10:59:41
So let's see the coding solution for this one. First of all, we are initializing our private hashmap where we are going to store the value or of
10:59:48
the key and its associated tree map as its subsequent value. Now let's
10:59:54
initialize our tree map with a new hashmap. Now for the set method, we are
10:59:59
given three values as an input. First one is the key, second one is the value associated and third one is the time
11:00:04
stamp. So for that we are actually going to store the value inside our hashmap and we are going to check that if the
11:00:12
key is not present. So then in that case we need to create a new entry for key
11:00:17
and it subsequent tree map. If that is not the case then we are going to simply
11:00:22
put down the value inside our time based on the time stamp and the value inside the tree map. Okay after creating the
11:00:28
new instance. So this is the set method. For the get method we are simply
11:00:33
checking that if inside the what is going to be the key portion for the tree
11:00:39
map for that we need to do map dot get key. So that is going to give us the value of the the value that we are
11:00:46
looking for inside the tree map and we are going to check that if the tree map is equal to null for that particular
11:00:51
entry then we can simply return null. If that is not the case then we need to check that what is the flow timestamp
11:00:59
associated with the current time stamp that we are given and we can check that if we don't find any entry we can simply
11:01:05
return null. If we do find an entry that is closest to that particular time stamp or that time stamp exactly then we can
11:01:12
simply return that value. And this is how the solution work. So let's try to run this code.
11:01:20
Okay seems like our solution is working as expected. Let's submit this code.
11:01:26
Okay, our code runs pretty good in terms of time and space complexity. There can still improvements be made but uh this
11:01:33
is going to be good enough solution. So once again the solution is present inside our GitHub repository. So if you
11:01:39
want you can go ahead and check it out from there. Thank you.
11:01:48
So we got a job at fang but we are not going to stop making late code videos because it's pretty fun for me. Uh so
11:01:54
today we are going to do median of two sorted arrays lead code problem. And if you see some of the popular companies who have asked this question there are
11:02:00
companies like Amazon, Apple, Goldman Sachs, Microsoft, Google, Bloomberg, Uber, Facebook, LinkedIn and by dance.
11:02:07
So that's why I'm paying my utmost attention. I hope you also enjoy the video.
11:02:12
So despite being a hard problem, this is a very well-liked problem on lead code. Basically we are given two sorted arrays
11:02:19
uh nums one and nums 2 and we are told that they could be of different size. So the size can be respectively m and n
11:02:25
that is given over here. Now we need to return the median of these two sorted arrays. We are also told that the
11:02:32
overall runtime time complexity should be big of log of m plus n. The solution I'm going to show you today is actually
11:02:38
going to do even better than this big of log of n + n. I'm actually going to solve this problem in big of log of
11:02:45
minimum value of either m or n. So before we understand this problem any
11:02:50
further first let's see that what does a median mean. So a median is basically any single
11:02:58
position inside any given array where everything on the left hand side and everything on the right hand side is
11:03:04
actually of same length. So whatever the amount of element it has on the left side, it the same amount of elements it
11:03:10
has on the right side. Now there could be two cases. There could be like odd numbers or there could be even numbers.
11:03:16
And for each one of them, I'm going to show you how to calculate the median. So suppose if we take this first example,
11:03:22
in this first example, we can clearly see that we are given three elements and based on the definition of a median,
11:03:28
everything on the left and everything on the right has to be same. So if we consider this element number five, five
11:03:34
is the position where uh the left of five is there is one element and the right of five is also there is one
11:03:39
element. So in this case five is going to be the median for this given array. Uh now if we take a look at this one in
11:03:46
this example things are a little bit tricky because this is an even number. So in the even case we actually have two
11:03:52
elements in the middle uh who form the middle portion such that their left
11:03:57
portion and right portion becomes of equal size. So in this case for this particular middle portion the left value
11:04:04
has one element and the right value also has one element. So both of these are part of the median but thing is in the
11:04:10
median there cannot be two values. So if such case arises which is for even numbers we are actually going to do the
11:04:16
average of them. So in this case we are going to do 3 + 4 divided by 2 which is 7 divided by 2. So we get the answer as
11:04:23
3.5 which is the median for this particular array. If we take this example again this is simple uh this
11:04:29
value number five again this falls in the middle. So because of that we are going to note five as the answer because
11:04:34
there are two elements on the right and two elements on the left. Now again for this case we held the value this four
11:04:41
and six that creates the middle point such that the left values and right values becomes of the same length. So in
11:04:48
this case uh the median is going to be 4 + 6 divided by 2. So again we get 10 divided by 2. So the answer is five. And
11:04:55
this is the median for this kind of case. Now after understanding what a median
11:05:01
is, first let's see these two examples. So it makes things more easy. So in the first example, we are given two arrays,
11:05:07
nums one and nums two. We can clearly see that they both are sorted array. Like this one only has one element but still it's sorted right. Uh and now we
11:05:14
need to find the median of these two arrays. So if we find the median of these two arrays, if we combine these
11:05:19
two arrays, we will get a array that looks like this. Uh that is sorted, right? because we need to find the
11:05:24
median of two sorted arrays. So this is the combined array. In this case, two is going to be the median because that is
11:05:30
the middle point where one there is one element on the right and one element on the left. Same way for this one, if we
11:05:36
try to see the length of this is actually 2 + 2. So the total length is four. Uh now if we make a combined
11:05:42
array, the combined array looks like this. And uh in this case, if we want to find the median of this one, we will
11:05:48
actually have to do an average of these two middle portions. So we'll do like 2 + 3 divided by 2. So we get the answer
11:05:55
as 2.5. And this is what we need to return as the answer. Uh so let's see
11:06:00
that what are going to be the different approaches to find the median of two sorted arrays. The first solution that
11:06:06
comes to our mind is a brute force solution. In the brute force solution, the idea is actually simple. If we just
11:06:11
combine these two arrays and create like a combined sorted array, we get an array that looks like this. Now once we have
11:06:17
this combined array, all we have to do is just find the median. So in this case the median is going to be this value
11:06:22
number five because on the left hand of the five there are going to be exactly five elements and on the right hand of
11:06:28
the five there are also going to be exactly five elements and this five is the answer we need to return. Uh so this
11:06:35
solution would give us the correct answer this brute force solution. But the issue with this solution is that in
11:06:40
order to create this combined sorted array we will actually have to complete this solution in big go of m + n time.
11:06:48
So that is a linear solution and the thing is that is not what we want. We actually want a log logarithmic
11:06:53
solution. So let's see that what is going to be the approach for the logarithmic solution.
11:07:00
Okay. So before we come up with the optimal solution first let's try to understand some really important concept. Suppose we are given two arrays
11:07:06
that are x and y. We are told that they both are sorted in ascending orders. Now we know that their length is actually
11:07:12
respectively five and six in this case. So the total number of elements we have is actually 11. If we do like 5 + 6.
11:07:19
Okay. So now here we are trying to find the median of two sorted arrays. And the
11:07:24
thing is the median how we are going to find is that okay currently we are given these 11 values. So these 11 values they
11:07:30
are combined of these two. Now this 11 we can actually create two partitions.
11:07:35
How we are going to create two partitions. So the logic we are going to use is that every single time whatever
11:07:41
the combined sum is we are actually going to do like + 1 divided by two. So in this case the value we will get is 11
11:07:47
+ 1. So that is 12 divided by 2. So 12 divided by 2 the value we are going to
11:07:52
get is 6. Uh so now first partition we will have to do is of six elements and
11:07:59
second partition we will have to do is remaining elements. So remaining elements in this case is 11 - 6. So that
11:08:04
this is going to be five elements. Right? And whichever is going to be the maximum element of this six. So maximum
11:08:11
element of these six is going to place somewhere over here in the middle and that is going to be our median. Now the
11:08:17
thing is how can we define that this maximum value is going to be the median. What are the properties we are going to
11:08:24
take for this six and five value partition that we are trying to create and the answer lies right in front of
11:08:30
our eyes that the sorted property has to be maintained. So what does the sorted property has to be maintained means? It
11:08:37
means that all of these six values that we are trying to create on the partition
11:08:42
they all has to be less than or equal to the values of the five on the right hand side. Okay. So that is a very important
11:08:50
property for us to understand. Uh I am speak telling this again that all those six values that we have on the left hand
11:08:56
side they have to be less than or equal to all the values on the right hand side. Why? Because we are trying to find
11:09:02
the median of two sorted arrays. If they're not sorted then it's like a big mess for us right? So because this is
11:09:09
the sorted properties maintained. Now what we are going to do is we don't care about finding these five values. All we
11:09:16
are going to put our focus is to finding these six values. Now these six values they can exist anywhere inside this x
11:09:23
and y. It could be possible that we take like three values from x and then we take three values from y and that is how
11:09:29
we create the six values. It could also be possible that we create like we take like two values from X and four values
11:09:35
from Y and that is also how we create this these six values. No matter whatever the logic we are going to use
11:09:42
we will always have to be certain that all the elements on the left hand side they have to be less than or equal to
11:09:47
all the elements that are on the right hand side and using this property we are going to come up with some very
11:09:53
interesting results. So the idea we are going to use is that first of all we are
11:09:59
going to take whatever the lesser value we have in terms of length among both arrays. So currently in this case the
11:10:07
lesser value of length we have is of array uh array x. So currently for this x the length we have is five right. So
11:10:14
what we are going to do is we are actually going to do 5 + 2. So 5 + 2 we get value of 2.5. If we take the ceiling
11:10:21
value we get the value to be two. Which means that now we are going to take two values from this x. So if we take two
11:10:27
values from this x we will get the values x0 and x1 that is on the left side of the portion. Now if we take two
11:10:35
values from the x which means total we are trying to find like six values because remember we are trying to find
11:10:40
like the two partitions. One partition is six second partition is five and all the six values has to be less than or
11:10:46
equal to these five values. So because we are trying to find the partition of six values which means we took two
11:10:51
values from the x. So we are going to take four values from Y. Now if we take
11:10:56
if we create a partition like this what is going to happen? Well all the remaining elements they are going to be
11:11:02
on the right side of the partition. So currently the remaining elements we have.
11:11:07
So now we have our two partitions right now these for these partitions again we
11:11:13
will have to make sure that this property is maintained. So how can we check that? Okay, over here we are 100%
11:11:20
certain that this x1 is always going to be less than or equal to whatever the value of this x2 is. Why? Because we are
11:11:26
told that this x array is already sorted. Same is true for this y array that this y3 is always going to be less
11:11:33
than or equal to this y4. This property is always going to be there. So there are no issues with that. But where the
11:11:39
issue comes? The issue comes uh to the place where we don't know that whether this x1 if that is less than or equal to
11:11:47
this y4. Same way we don't know that whether this y3 if that is less than or equal to this x2. So in either case we
11:11:55
are going to do the following. First we are going to take the smaller value. Then we are going to find that what is
11:12:02
the partition we are trying to make depending on the starting and ending value. So currently the starting value over here is zero and the ending value
11:12:08
is four. Okay. Okay. So we will if we do that we get the value of two. Now we are going to take two values from here. If
11:12:15
we take two values from here then we will have to check that what are the remaining partition for y and how many
11:12:20
values we are going to take from y. So currently from y we are going to take four values. Now for all of these values
11:12:26
we are going to check that whether this x1 is smaller than this y4 and same way whether this y3 is smaller than this x2.
11:12:33
Uh once the moment we find both of them to be matching uh great. If we don't
11:12:38
find anyone to be matching, suppose we find out that this x1 is actually greater than this y4. If that is the
11:12:45
case, then what needs to be done? Well, the idea is simple because this is a greater value and this is a smaller
11:12:51
value which means that this x1 has to go on the right side and this y4 has to come on the left side. Now you will ask
11:12:57
that why both of them has to happen simultaneously. Well, if both of them does not happen, how are we going to
11:13:03
maintain the number of elements that are needed? because currently the number of elements that are needed are six on this
11:13:09
side and five on this side. So we have to make sure that we maintain that property. So how can we do that? We can do that by shifting this ending point to
11:13:16
come on this side and rather than keeping like both of these values, we might only keep one value over here and
11:13:22
we will try to keep four values from here. And same way if we find that this y3 is greater than x2 again we are going
11:13:29
to repeat the same process by shifting the starting point on the right side and keeping repeating the same process. So
11:13:36
let me quickly explain the whole process with some examples and then it is going to make things a lot easier to
11:13:41
understand.
11:13:47
Okay. So now suppose this is the example of x and y values we are given. I have calculated the total number of elements
11:13:53
we have which is 11 in this case which means as explained previously uh the left partition that we will have to make
11:14:00
that is combined of x and y elements that has to be of size six. Now for this x partition what we are going to do is
11:14:06
depending on the starting and ending value divided by two we are going to calculate that how many elements are
11:14:12
needed in the x position and based on that we would calculate that how many elements are needed in the y from the y
11:14:17
side or from the y side of array based on this formula of like 6 minus whatever the value we achieve from this x
11:14:23
position and then we will try to compare the values. So first of all okay currently this value is 0 this value is
11:14:29
four if we do like 0 + 4id by 2 we get value as 2. So now which means that
11:14:34
inside this x portion we are going to take two elements which means for this y pos portion we will have to take four
11:14:40
elements from this y. So now because this is the left portion we are going to take the left most two elements in the
11:14:46
inside the left array which is 0 and three in this case and from this y portion we will have to take four
11:14:51
elements which means we are going to take the first four elements over here. Once done that basically now we have our
11:14:58
left partition setup. So now because we have our left partition set up we can automatically create our right partition
11:15:03
from the remaining values which are now we know for sure that this three is always going to be less than this five
11:15:10
because they both belong to x array and same is true for these two. The thing is now we are going to do the cross
11:15:16
comparison. So currently this three is less than 13 which is great that we don't have to do worry about anything.
11:15:22
The thing is for this 12 12 is actually not less than this five. 12 is actually
11:15:28
greater than 5 which means that because we have some element inside this y array
11:15:34
which is greater we will have to move this one on this side and we will have to move this value on the left hand
11:15:40
side. So now what we are going to do is because we will have to add more values from the x we are actually going to
11:15:46
shift our starting point. So where we are going to shift our starting point? The idea is that previously we had the
11:15:52
values of s + e equal to 0 + 4 / 2 like okay this value. So we had the middle
11:16:00
point as 4 / 2 is equal to 2. So now because this is a binary search we are
11:16:06
actually going to do like 2 + 1 for the starting point. So now our new starting
11:16:11
point comes at position number three. Okay. So now this is the new starting point. This is the new ending point. Now
11:16:18
again we are going to use the same logic. So now for this X partition a few things have changed. So currently our
11:16:24
starting position is three, ending position is 4ID by 2 which is 7 by 2. So we get the value 3.5 but we use the
11:16:31
ceiling value. So now from this X position we will have to take three elements. So if from the X portion we
11:16:37
will have to take three elements which means even from the Y portion we will have to take three elements. So let's do that. So this is how the two partitions
11:16:44
are going to fall. Now this time now again we compare okay so this five is less than 12. So which is good. Now this
11:16:51
8 this 8 is still greater than six. So again we will have to move one element from this uh to the right hand side. So
11:16:58
again we are going to update the value inside our x pointer to move the s element to the next side. So how we are
11:17:04
going to do it? Okay currently this value is three. This value is four. So now again we are going to repeat the same process. So we get the value. Okay
11:17:12
3 + 4 divided by 2. So we get the value of 7 / 2 which is 3. Okay. So now we get
11:17:18
the value to be 3. 3 + 1. So this is going to be the new start point. So currently our start and end point they
11:17:25
both fall on the same position. So this is the start point. This is the end point. Now again for this x partition
11:17:32
let's see that how many elements we are going to need. So we will have value 4 + 4 divided by 2. So 4 + 4id by 2 is going
11:17:38
to be 8 divided by 2. So the value is going to be four. which means we are going to need four values from the X
11:17:44
partition. So from the Y partition we are going to need two elements. So let's do the math. And now let's create the
11:17:51
new partitions.
11:18:10
Okay. So these are the two partitions we have. Now let's compare. Okay. So 6 is less than 8. Great. 2 is less than 11.
11:18:17
Great. So now we have created two partitions such that on the left hand side we have six elements. On the right
11:18:23
hand side we have five elements. We were able to calculate that using the total elements we had. The sum we used was
11:18:29
total + 1 divided by two. So 11 + 1 divided by two. So we get six elements on the left hand side. Now from these
11:18:36
six elements because the total length was odd. So because of this was odd. So what we are going to do is from this
11:18:42
left portion we are going to select the maximum value. Now you would say that hey do we need to calculate all the
11:18:47
values on the left portion to calculate the maximum value and the answer is no. Why? Because all we have to do is check
11:18:52
these two values. Whichever is greater value is going to be the maximum value on the left portion because all of these
11:18:59
values are sorted. So amongst first four values this is the maximum value and same way amongst these two values this
11:19:05
is the maximum value. So if we compare the maximum value between these two basically we will get our desired answer
11:19:11
and in this case the answer is going to be six and because this was the odd case this six is going to be the median that
11:19:18
we are looking for and this is going to be the correct answer. Now let's take one more example with odd case and see
11:19:24
that how things work out over here. Suppose this is the second example we are given. I did some math. So total
11:19:29
number of elements we have is 12. Which means that if we want to calculate that how many elements we need in the left
11:19:34
portion basically we are going to do like 12 + 1 divided by 2. So in this case we get the answer to be 6.5 but we
11:19:40
choose the ceiling value uh which is we choose the floor value which is going to be six. Now for this x portion uh we are
11:19:48
going to do like starting plus ending divided by two. So first currently the starting and ending positions are this
11:19:53
one. So we get the value to be now which means we are going to take two elements from the x portion. So if we are going
11:19:59
to take two elements from the x portion, we are going to take four elements from the y portion. So let's do that.
11:20:05
These are the two partitions that we have created. Again let's compare the values. So first 8 is less than six. No,
11:20:11
that is not true. 8 is actually greater than six. The moment we find 8 is greater than six, we will have to move
11:20:16
this eight on the right hand side and we will have to move this six on the left hand side. So let's do that process. So in this case now what we are going to do
11:20:23
is we are actually going to update our end value to come on this side. So again previously what was the end value? The
11:20:30
previous end value was position four. Now the new end value we are going to create is we are going to find the middle value. So the middle value
11:20:36
currently is 0 + 4 depending I'm talking about these like starting and ending values. So 0 + 4 divided by two. So this
11:20:43
is the middle value is 2. So for this ending value we are actually going to do 2 - 1. So now let's update our ending
11:20:49
position. So our ending position is now going to come at this position number uh
11:20:55
one. Okay. Now again we have the updated value of starting and ending values. So now let's try to calculate this x
11:21:01
portion and y portion again. So for now this time this x portion is actually going to be 0 + 1 divided by 2 which is
11:21:07
going to be like 0.5. But again we are choosing the floor value. So we will get the value to be zero. Which means we are
11:21:13
going to take zero values from this x portion. So if you're taking zero values from this x portion which means that we
11:21:19
will have to take six elements from this y portion which is okay cool. No nothing wrong with that. Okay. So now we have
11:21:26
these two values. Now let's do our partition. So now we have created our two portions. Now in this case because
11:21:33
from this X portion we are not going to take any values. We currently have zero values. Right? Now the thing is
11:21:38
previously we have been comparing like this. The thing is currently in the X portion we actually have zero elements.
11:21:44
So if we have zero elements how we are supposed to compare with this one. The idea we are going to use is that every
11:21:50
single time we are going to compare the we are going to consider that this like first value is actually negative
11:21:55
infinity and this last value is actually positive infinity. So the minimum and
11:22:01
maximum value possible on each one of side. So in any case we come up to this
11:22:06
edge case where we need to find we don't have any values on one portion we can we don't get stuck. So we will try to
11:22:13
consider this to be negative infinity value. Now negative infinity value is always going to be less than whatever
11:22:18
value we have. So it's always going to be less than 15 which is great. Now we compare these two values. So 7 is
11:22:24
actually greater than zero. So because 7 is greater than zero. Now what we will have to do is we will have to move our
11:22:31
uh seven to go on the right side and we will have to try to bring one element from this uh x portion. So let's do that
11:22:38
do that. So now we are again going to update the values of our starting and ending values. Now this time we will
11:22:43
have to update the start value to go on the right side. So currently the starting position is zero. The ending
11:22:50
position is one. Okay. So the new start value we will have to find the middle value. So middle value is going to be 0
11:22:55
+ 1 divided by 2 which is going to be 0. We have already established we are trying to taking the ceiling value. So
11:23:01
the new starting value is going to be 1. So let's update that. And now we will try to recalculate the whole thing. Now
11:23:07
this x pos the number of x element is going to be 1 + 1 divided by two. is going to be one. So we are going to take
11:23:14
one value from this x position which means we are going to take five values from the y position. So let's compare x
11:23:19
and y positions. So now we have a two partition setup. So if we compare the zero with 7, the 0 is less than or equal
11:23:26
to 7. That is correct. If we compare the six with 8, 8 is 6 is also less than or equal to 8. Which means that this is a
11:23:33
correct partition amongst left and right values. Now in this case the combination
11:23:38
value is actually even for left and right case. So because this is even value what we are going to do is we are
11:23:45
going to pick the maximum value from this one. So maximum value from this one is going to be six and we are going to
11:23:51
pick the minimum value from this portion. So minimum value from this portion is going to be seven. Now again
11:23:56
same logic we are only going to compare these two values to find the maximum value. So in this case we'll get that
11:24:01
value to be six. uh in order to find the minimum values we are going to only compare these two values and in this
11:24:06
case the value we are going to get is seven. So now we are going to do the average of these two. So we will get the value of 6 + 7 divided by 2 which is 13
11:24:13
by 2. So 6.5 that is the answer and that is the median we need to return and that
11:24:20
is the whole logic behind using this technique. every single iteration we are
11:24:25
updating the values of uh s uh starting and ending point only in the array that
11:24:31
has the smaller length. Uh so in this case both the times x had the smaller length. So we are only working on that
11:24:38
and depending on that we are generating our answer and we are able to find successfully the median value. So if we
11:24:44
calculate the time complexity in this case the time complexity is actually going to be big of log of minimum of m
11:24:52
or n and in this case whatever the minimum value is we would be able to find the uh median easily. You see space
11:25:00
complexity in this case the space complexity is also going to be bigo of one constant space. Why? Because in
11:25:06
order to store like uh the portion we don't have to store this whole things. We are only concerned with four elements
11:25:12
like the minimum of x the minimum of y maximum of x and maximum of y and using
11:25:18
these four elements we can do all sorts of magical things. So this is a very good time in space complexity and this
11:25:24
is a very tough question in my opinion. So if you are able to crack this in an interview all the companies would be
11:25:29
like more than happy to have you as the candidate.
11:25:36
So first of all we are going to compare the length of nums one and nums two. The idea is that whichever has the smaller
11:25:43
length we are going to keep it first. So if not we are just going to call it
11:25:48
recursively again with the different inputs. Now we are going to initialize two variables called x and y and uh we
11:25:55
are going to assign the length of respective numbers. Remember x is the smaller length and y is the greater
11:26:02
length. We are also going to assign two variables called start and end. Uh so start position is going to have the
11:26:08
value zero and end position is going to have the value of whatever the value of x is. Now we are going to run our while
11:26:14
loop that while start is less than end. Now first we are going to calculate that what is what should be the x portion. So
11:26:21
we are going to name it as x part. Once we calculate the x portion it's easy to
11:26:26
calculate the y portion. Okay. Now we are going to calculate four important characters. uh those four characters are
11:26:32
left value of x, right value of x, uh left value of y and right value of y. Uh
11:26:38
now each one of them we are for every single left portion we are going to see that if that subsequent like x part or y
11:26:45
part if that value is zero we will have to put like minus infinity or plus infinity for those values. If not we
11:26:52
will put whatever the uh subsequent value we can find from this nums array.
11:26:58
So let me calculate those four values. Now we have our four values that we are
11:27:04
going to need. Now we are going to compare that if the x left and y left if they are both less than y right and x
11:27:12
right. If that is the case which means we can simply return we have found the correct uh portion and depending on
11:27:18
whether the total number of values are odd or even we can simply return the answer. And if that is not the case we
11:27:24
will have to update our start and end variables. So first let's calculate for the correct case. Now we will have to
11:27:31
calculate that whether the sum of these nums one and nums two if they are odd or even. So if they are odd value we will
11:27:38
simply pick like the maximum value that we have on the left portion. And if it is like the even value we will pick the
11:27:46
maximum value from the left portion and minimum value from the right portion average of both of them. And if that is
11:27:53
not the case which means the value is odd. uh so in that case we can simply return the maximum value. If that is not
11:28:00
the case we will have to check that which one uh end we will have to update. So first we will see that if the given x
11:28:07
left if that is greater than y right which means we will have to update our uh end value to come before mid else we
11:28:15
will have to update our uh start value. Basically it we should get our answer
11:28:22
this way. If we don't get our answer, we can simply return zero outside the loop. So do we don't get a compilation error.
11:28:28
Let's try to run this code. Okay, seems like our solution is working as expected. Let's submit this code.
11:28:34
And our code runs pretty efficiently compared to a lot of other solutions. And I will be posting this solution in
11:28:39
the comments. So you can check it out from there. Thank you.
11:28:57
Link list is a very popular data structure and it is nothing but a different way to store data inside the
11:29:04
memory of computer. So let's understand that what is the basic concept of a link list. Now link list typically defines
11:29:12
any particular value that you wants to store in a node like block that has two
11:29:17
separated entries. First entry is pretty common. You can store anything you want. It can be int integer character or any
11:29:23
value that you are trying to store. On top of it you are also given this value
11:29:29
that contains the memory block of the next value uh inside the subsequent
11:29:34
value of the link list. And next node also looks very similar where it also contains two partitions where this can
11:29:41
contain the any particular value that we are trying to store and then we have a memory address that points to the next
11:29:48
element inside the subsequent link list and it keeps on going on so on and so forth. Now there is some terminology
11:29:54
that you need to understand. First terminology is that the very first element inside any particular link list
11:30:00
that is going to be the starting point that is all that is given to us as part of the beginning of the link list and
11:30:07
that is referred as the head of the link list. Now the very last element that we
11:30:13
currently have inside the link list is also going to have the similar structure. The only difference is that it is going to contain a value but the
11:30:20
very next element it is pointing towards this is going to be a null value. And
11:30:25
this very last element inside the link list is referred as the tail element of the link list. Uh so link list is
11:30:33
basically comprised of uh two simple variables head and tail and everything
11:30:38
in between. Now notice that all of these values they are dynamically allocated.
11:30:44
So we know that in an array we have a fixed memory size and we have a fixed size where every every single value is a
11:30:51
continuous block of memory. That is not the case inside the link list and this is a dynamic data structure. So because
11:30:58
this is a dynamic data structure this can grow and shrink on its own without any issues and that's what that makes
11:31:06
one of the most popular characteristics of a link list. Next thing is link list
11:31:11
actually has multiple different types. So first type is a singly link list where a singly link list defines that we
11:31:18
only know that what is going to be the next element inside our uh link list and
11:31:24
that's it. That is the only information we have nothing more than that. And this is an a simple example of a singly link
11:31:31
list where we basically have our head node and we have our tail node and
11:31:36
everything is in between and it only points to the next element. That's it. So let's say for some reason we are
11:31:42
located at this value X. Then we know that after value X what is going to be the next subsequent value inside the
11:31:49
link list but we don't have any way to identify that what was the previous value where we derived this value X from
11:31:57
and this is called a singly link list. This is the most basic type of link list. Second link list is a doubly link
11:32:03
list. Now a doubly link list is slightly more advanced and it has some more additional benefits. basically and this
11:32:10
wl link list contains a node like structure like this where you can notice
11:32:16
that we actually have two spaces to store the memory block not just one and
11:32:21
as the name suggest uh this serves basically double functionality. So we
11:32:26
are going to have our very first head node as this and inside the head node we
11:32:31
are going to have our value x that we need to store. We are also going to have this memory block that is going to point
11:32:37
to the next memory block. On top of it, we are also going to have a very first
11:32:42
memory block that defers that what is the previous block that called this
11:32:48
memory block. Now for the head value because this is the first element. No one else is calling this this node. So
11:32:55
this node is also going to have the null value or this memory block is going to have null value. Then uh this memory
11:33:02
block is going to contain the address of its subsequent Y block. But on top of
11:33:08
it, this Y block starting point is also going to contain the address of the
11:33:14
previous memory block that called Y. And same way at Y, we can point to the next
11:33:19
node. And the be beginning of this uh Z node, we are going to be able to point
11:33:25
back to the node Y. And the last node of Z is going to be pointing towards the null value. And this is defined as the
11:33:31
tail node. So now notice that inside the head node we have the starting pointer
11:33:37
or the previous node that called us as null. So this would be referred as the head node. And the same way when we
11:33:44
identify that the no next node is null then that would be defined as the tail node. And the last one is a circular
11:33:51
link list. Now for the circular link list there can be two types. There can be circular singly and there can be
11:33:57
circular doubly. But let's just keep it straightforward. Let me give you a very simple example. Basically, we are
11:34:03
pointing uh next nodes in subsequent fashion. But uh in typical link list, we
11:34:09
have the next node uh or the last node of the link list point towards the null value. In this case, this does not point
11:34:16
to a null value, but instead this memory block points back to the very first element and this creates a sort of like
11:34:23
a cycle inside the link list and that's why this is referred as a circular link list. So there can be two types circular
11:34:29
singly and circular doubly. In both the cases, we are going to have the nodes point towards subsequent memory block.
11:34:36
So if this was to be a circular doubly link list, we would have two blocks of memory being stored at every single
11:34:42
value and then eventually the these blocks would be connecting with each other in this fashion. So I know link
11:34:49
list sounds different but trust me after we are done with the 14 popular
11:34:55
questions from the lead code you would understand every single concept from the link list. Now let's note some of the
11:35:02
benefits of link list. Uh it's quite straightforward. the benefits because number one this is a dynamic data
11:35:09
structure so memory management is much more uh flexible and much more
11:35:14
convenient we can add and red remove elements at will and we don't have to do
11:35:19
much thing about it next thing is that it is also uh scalable so we can add as
11:35:25
many values as we want as we see fit plus link list is one of those data structures that work really well with
11:35:31
other data structures like graph entry because many times In representing graph, we will have to point like one
11:35:38
node pointing to the different node pointing to the different node and that's where we create something called adjacy list and that you will learn more
11:35:46
about when we reach to the graph topic. But overall just understand that link list is dynamic in nature and it has
11:35:54
good amount of value whenever it comes to like uh removal removal of any
11:36:00
particular node and insertion of any particular node. So let me give you an example. Let's say that I currently have
11:36:06
a link list of these five different values. Now for all of these values they
11:36:11
are pointing towards each other and this is a singly link list. Now say that somewhere in the middle I want to
11:36:18
include one node. So if this was array I'm dealing with a fixed size uh data
11:36:24
structure and I need to do lot of things in order to add this one particular node. But in link list it is going to be
11:36:30
very simple. All I need to do is iterate to the node after which I want to add
11:36:35
this node. So let's say that I want to add this node after this node X. Then this node X is currently pointing
11:36:41
towards this Y value. So instead of this pointing towards Y- value, I'm going to
11:36:47
store this information somewhere in a temporary variable that what is the memory location of the Y. And then I'm
11:36:52
going to have my X point towards this Z character. And then the next value that
11:36:58
should be in the node, I'm going to take it from this temporary variable and store it inside the Z. And basically I'm
11:37:05
going to delete this node and I'm also going to remove the temporary node because now we no longer need it. So see
11:37:10
how easy it was for us to add any particular node inside the link list. And this is where the true power of link
11:37:16
list lies. Uh insertion and deletion and all of these operations are pretty
11:37:22
simple and pretty easy to do. Now let's talk about some of the common time complexities for link list and different
11:37:28
operations that we can perform. Number one operation we can do is the insertion insert operation. Now inserting at the
11:37:35
beginning or at the very first uh value inside the link list is going to be big of one because all we are doing is just
11:37:42
adding one more node at the front and then whatever the memory address this had we are just pointing it over here
11:37:47
and the very first element this is marking we are marking this as the head of the link list. If we have to insert
11:37:54
somewhere in the middle or towards the end then it becomes a little bit complicated because remember in the link
11:38:00
list we are only given the very first node that is currently present that is the head of the link list. So let's say
11:38:06
that if we have to insert it somewhere in the middle then first we will have to hop across all of these elements and
11:38:12
then we can do the insertion. So the operation to insert value is still big
11:38:18
of one. But the thing is in order to reach to that particular element that would take big of end time. So whenever
11:38:24
you have to insert somewhere in the middle or towards the end and if it is a single link list then it it is going to
11:38:29
take big of end time. Second operation is delete. Same way for the deletion. If we like any particular deletion is big
11:38:37
of one. But in order to reach to the point that we are trying to delete that takes big of n. So you will have to
11:38:43
distinguish this when you whenever you are trying to thinking about time complexities. Uh next operation that we
11:38:49
can do is iterate over the link list. So iteration over the link list is going to take big of n because we will have to
11:38:54
iterate over every single element and it it you can do it using a very simple for loop or a while loop and the process is
11:39:01
quite straightforward. Next operation inside the link list is a search operation. Now searching an element is
11:39:08
going to take big of n time because we don't have a way to index values. So
11:39:13
whenever you need to search an element you will have to iterate over every single element to make sure that whether
11:39:18
that element is present or not. So these are sort of the main operations that we deal with and then uh with the link list
11:39:25
one more thing I would like to mention is that there is a very popular scenario in link list where you are trying to
11:39:30
find that whether there exists cycle inside the link list or not. So typically we use an approach called fast
11:39:36
and slow pointer and this is a very good way for us to detect cycle on top of it.
11:39:41
This is also a very good way for us to find the middle pointer of the link list as well. So we will see the examples of
11:39:48
this technique being applied in many different questions. So now this is my
11:39:54
introduction towards link list. I hope you understood the concept. Hello friends, we are not employed by fang
11:39:59
company. So let's not stop lead coding till we get there. Today we are going to do reverse uh linkless problem and uh
11:40:05
essentially this is a very easy but very important lead code problem as it has been asked at bunch of different
11:40:11
companies. So this problem has been asked in companies like Amazon, Microsoft, Apple, Bloomberg, Facebook,
11:40:17
uh Google, Nia, Adobe, Uber and also IBM, eBay, PayPal, other companies like
11:40:24
Goldman Sachs and then bite dance and a few other companies. So I'm paying my
11:40:29
utmost attention. I hope you also enjoy the video.
11:40:36
Hello friends, I got my results back from the from my Goldman Sachs interview and I didn't clear it which means that I
11:40:42
have a long way to go and I still have to do lot of work on my coding and lead coding skills.
11:40:51
This is a lead code easy problem and it is one of the most liked problems on lead code. Basically we are given a head
11:40:57
of a singly link list and we need to reverse the given list and then we need to return the reverse list. So problem
11:41:03
statement is quite easy to understand in and even if we see the example the example is also quite easy to
11:41:09
understand. Basically we are given a list like this 1 2 3 4 5 and we are at
11:41:14
this position and we are given this head value of this link list and basically we need to return the reverse list. So in
11:41:21
this case the reverse list is going to be 5 4 3 2 1. So essentially we are just
11:41:26
iterating over in this direction and this is what we need to return. Now the thing is there happens to be little bit
11:41:32
more complexity because we are told that this is a singly link list. So in singly link list all the elements are just
11:41:40
stored in a single manner which means that this element only knows that what
11:41:45
elements comes after it. it does not know that what is the element before it that is pointing to this position. So
11:41:52
this is the concept of a singly link list and we will see that how can we solve this problem.
11:41:59
Okay. So we need to reverse the link list and we are told that the link list we are given is actually a singly link
11:42:05
list. The thing is that what is the property of a singly link list that the link the every node in the given link
11:42:12
list actually has the value of that particular node and also has the pointer towards the next node inside the link
11:42:19
list. And whenever we encounter that next node is actually pointing towards
11:42:25
null value we can determine that this is the end of the given single link list.
11:42:31
The issue over here is that we know that at any single position what is the value
11:42:36
after it using this next pointer but we don't know that what was the value before it. there is no way for us to
11:42:43
identify this particular item. Which means that our aim is to find that how to reverse this link list. And in order
11:42:50
to reverse this link list, what we can do is rather than pointing towards the next pointer, we can if at any given
11:42:56
position for all the nodes, if we just point it towards the reverse direction and basically start our link list
11:43:03
traversal from the last node, uh we can simply return the reverse link list
11:43:08
immediately. And this is the approach we are going to take. Now the question comes that how at any point we can
11:43:14
actually uh originally we were pointing on this side. How can we start pointing
11:43:19
on the reverse direction from any single node and in order to do that what we will have to do is we'll have to keep
11:43:25
track of the previous character or previous node as well and apart from
11:43:31
keeping track of the current node. So the approach we are going to use in this case is that every single position
11:43:38
suppose we are at this element. So this is the current element we are at right from this current element we know that
11:43:44
how to get to the current dot next which means that how to go to the next element we already know that know that the
11:43:51
question is we don't know that how to go back. So what we are going to do is we are going to keep track of a previous
11:43:57
character or previous node that will always be behind this current node. So in this case this would become our
11:44:03
previous node and all we will have to do is that over here the current do next is
11:44:08
actually pointing towards this node three. So rather than current next pointing towards this node we are going
11:44:14
to have current.next point towards the previous element and we are going to do
11:44:20
iteratively for all the values. So initially at at the beginning this would
11:44:25
be our previous and this would be our current. So over here the this value will be pointing towards this on this
11:44:33
side. So null value. Now again we will switch our values for previous and
11:44:38
current. So this would become our previous and this would become our current and again we will flip the value
11:44:44
and again we will repeat the same process. So this would become our previous. This would become our current. Again we will flip the direction and at
11:44:52
the end this would become our previous. And if we see the previous next element,
11:44:57
it would be a null sequence. So we would know that okay, this is the end of the original link list. So this has to be
11:45:03
the start of the new link list. And then we can just start iterating over. Which means that we would have taken care of
11:45:10
all of these pointers. And now we can simply return the reverse link list in
11:45:15
this fashion and this would be our answer. So if we see the time and space complexity in this matter, the time
11:45:22
complexity for this one would be bigo of n and the space complexity would only be
11:45:28
big of one because at any given position all we have to do is just keep track of couple of variables nothing more than
11:45:34
that and that that should take care of all the scenarios.
11:45:42
So first of all we are going to create a new list node and we are going to name it as previous and uh we are going to
11:45:49
initialize the value as null and we are also going to create a list
11:45:55
node called current and we will have it start at the head value.
11:46:04
Okay now we are going to iterate over the given link list. So while current is not equal to null, we are going to keep
11:46:12
running in the loop and inside the loop uh essentially we
11:46:18
have to uh flip the values between current and previous. So what we can do is current uh dot next
11:46:29
would be our previous node. And then for the previous node we will
11:46:36
have to flip it to current node. And for the current node we will have to go to
11:46:42
the next node in the original single link list. So for that we will have to create a temporary variable. So let's
11:46:49
create a new node and we are going to name it as temp and we are going to
11:46:54
store the current do next node over here. And now for the current node we
11:47:01
are going to point it to this temp because notice because remember over here we are updating this current dot
11:47:07
next value. So that's why okay and uh yeah I think this is it after this loop
11:47:13
ends uh we should have our uh link list reverse so we can simply return the head
11:47:20
as previous uh variable and uh this should be it. Let's try to run this
11:47:26
code. It seems like our solution is working. Let's try to submit the code.
11:47:33
Okay, our code actually runs 100% faster than all the other solution because it's
11:47:39
running in constant time and uh I would be posting this in the comments. You can check it out from there. Thank you.
11:47:52
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do middle of the link list
11:47:58
problem and this problem can be a great problem to start any technical interview
11:48:03
and this problem has been asked by bunch of top tier companies like uh Amazon, Apple, Facebook, Google, Microsoft,
11:48:10
Goldman Sachs, Bloomberg and JP Morgan. So these are some of my dream companies. So that's why I'm making these videos. I
11:48:16
hope you also enjoy them. So this is a lead code easy problem and
11:48:21
basically we are given the head of a singly link list and we need to return the middle node of the link list. Uh we
11:48:27
are also told that if there are two middle nodes we need to return the second middle node. So let's try to
11:48:32
understand this with the given example. So over here we are given an example where we are given five different nodes.
11:48:38
So five nodes is odd number. So basically we can determine that okay the middle number in this case is going to
11:48:44
be the exact uh number that is at the third position. So we need to return this one as our answer. Uh meanwhile
11:48:51
inside the example two we are given a link list with six elements and since this is an even number there can be two
11:48:57
different nodes we can treat as as the middle nodes uh three and four and we are told that if there are two middle
11:49:03
nodes we we need to return the second middle. So in this case we will return the value number four and it is pretty
11:49:09
trivial to understand the problem statement. Let's see that what could be the different approaches.
11:49:14
So suppose we are given an example like this and we need to find that okay what is the middle value of this given uh
11:49:20
link list. The question is that in order for us to find the middle value first of all we need to find that what is the
11:49:26
total length of this given link list. Uh and in order for us to find the length we will have to iterate over this given
11:49:32
link list. That is a given fact right? But thing is uh only when we find out the length it it is not pretty easy to
11:49:39
get the middle value. Why? Because this is a single link list. So even uh over here if we reach and if we iterate
11:49:46
through all the values and we find that okay the length in this case is going to be seven. So the middle element is going
11:49:51
to be length by two which is going to be uh the element located at position number four. Uh and in this case uh
11:49:59
still if we want to attain this position number four we will again have to iterate over all the elements to get
11:50:05
this value. Why? Because this is a singly link list. So if we want to uh now we want to address two issues at
11:50:12
once. First uh issue we want to address is that we want to find the length and second issue we want to address is that
11:50:18
we want to find the length in a once we know that what is the length and what is the middle point we need to find the
11:50:25
middle pointer immediately. So one solution that comes to our mind is that we can actually create an array and we
11:50:31
can we are going to initialize this array with the value 100. So you will ask that why did I choose this value
11:50:37
number 100 and why not anyone anything else because inside the given input we are actually told that there is a
11:50:42
constraint that the maximum number of nodes we can have is going to be 100. So
11:50:48
that's why I chose 100. Now once we have that we are also going to have a variable called length and we are going
11:50:53
to initialize it to zero and every time we hop on to one element inside the link list we will update we will do length++
11:51:01
and uh we are going to repeat this up until we reach to the null element and apart from updating the length value we
11:51:08
are also going to add whatever the node we iterate over inside our array as well
11:51:13
and how it will help us let me just quickly show it to you. So suppose uh our given array. So the these are the
11:51:19
index values. Let's start adding the actual uh list node values. So first of
11:51:25
all we are at this position. So we will add value number one. Then we will do a length ++. So this becomes one. Then we
11:51:32
will add value number two and this would be also become two. And eventually we would have added all the values. So our
11:51:38
length would become seven. And over here we would have added all the values. Now we have added all the values. uh we
11:51:45
need to return the middle value. So middle value is actually quite simple to get. All we need to do is that for this
11:51:51
particular array we need to return the value located at whatever the length divided by two place is. So in this case
11:51:59
the length is 7. So 7 divided by 2 is actually going to be three. Why three?
11:52:05
Actually it becomes 3.5. But we are going to use int and we are going to use floor uh function. So we need to return
11:52:13
the value located at the third index which is this one. So this is the third index and the value uh is four. So a of
11:52:21
three in this case is going to be four. So we will return this four as an answer and this would be our solution. And now
11:52:28
you will ask that okay rather than in this case we had odd numbers. What if we had even numbers? Even if we had even
11:52:34
numbers even if we only had let's say six elements. So over here the length would be six. So if we do 6x2 the value
11:52:42
is going to be three. And even in this case we will have to return the element four. Why four? Because uh remember that
11:52:48
if we only have six elements we would have uh two middle pointers and those two middle pointers are going to be
11:52:54
three and four and we need to return the second middle pointer and which is going to be four. So this can be our solution.
11:53:00
This would work perfectly fine. No issues with that. Uh but uh this will only work just for the sake of solving
11:53:07
the lead code problem. There are a couple of issues with that. First issue is that we are choosing this value
11:53:12
number 100 which we should not choose because uh there can be million entries that your interviewer is going to grind
11:53:18
you over it. Uh second issue is that we are using this additional data structure array to solve this problem. Like let's
11:53:25
see the time and space complexity for this one. So the time complexity in this case is going to be big of n and the
11:53:30
space complexity in this case is also going to be big of n. And uh your
11:53:35
interviewer is going to ask you that can you solve it in better time in space complexity and the answer is yes. So let
11:53:41
me quickly show you how.
11:53:46
Okay. So we are going to use the same example and we are going to see that what would be the better approach like
11:53:52
in order for us to find the middle pointer what we need to do? we need to re somehow reach to the end of this
11:53:58
given list and after we reach the end of the list we need to find that okay what was the middle point and whatever the
11:54:04
middle point we'll need to return that. So the question is do we really need to
11:54:09
use an array for this one? And the answer is no. A better approach is uh something which is much more beautiful
11:54:15
and very intuitive solution which is two pointer solution. We are going to have two pointer. One pointer is called fast
11:54:21
and second pointer is going to be slow. Initially for the fast and slow pointer we are going to start at the initial
11:54:27
position and both of them have a special property. So slow is going to uh do one
11:54:33
iteration. Meanwhile, fast is going to jump by two steps. And uh we only need
11:54:39
to do this until fast reaches to the null or fast next reaches to the null.
11:54:45
The moment it reaches to this point, whatever the value of slow pointer is at would be the middle point of the given
11:54:52
list and we need to return that. Uh confused? Let me show it to you how it would work. So first of all, let's just
11:54:58
create two parameters fast and slow over here. This is a fast parameter at the
11:55:03
top and I'm also creating a slow parameter at the bottom. Now let's start doing the jump. So fast is going to do
11:55:10
two jumps at a time. So fast will come over here. At the same time slow is going to do one jump at a time. So slow
11:55:16
will reach over here. Again fast is going to do two jumps because fast is not null or fast. Next is not null. So
11:55:22
fast will reach over here and slow is going to do one jump. So slow is going to be here. Again fast is going to do
11:55:28
two jumps. So fast will end up over here. Uh again slow slow will also do one more jump. So slow will reach over
11:55:35
here. Now if we check at this position uh fast is not null but fast. Next is
11:55:43
actually null. So because this is null this would be our terminating case. So
11:55:48
the moment we reach that okay fast. Next is null fast pointer cannot go any way further. Which means whatever the
11:55:54
position of slow pointer is that should be the middle of the given link list and which is the case over here that uh the
11:56:01
middle the this value at slow pointer is actually the middle of the list and we simply need to return that we don't need
11:56:07
to do any additional work and this is a very beautiful solution. If we see the time and space complexity in this case
11:56:12
the time complexity is actually going to be go of n divided by two. Why n divided by two? Because notice that this fast
11:56:19
pointer actually do two jump at a time. So we will reach the end of the list quicker. But the thing is overall in
11:56:25
general we can uh mention this as of n. And in terms of space complexity all we
11:56:30
are doing is just keeping track of couple of pointers. Uh and that takes constant uh space. So it would be
11:56:37
constant space algorithm. So this would this is a very optimal time and space complexity compared to our previous
11:56:43
approach. And let's see the solution. So we are going to initialize two
11:56:49
parameters slow and fast and for both the parameters we are going to uh put the first value as head.
11:56:56
Now we need to iterate over the given uh list node until we reach that the either
11:57:02
the fast node is null or uh the fast next is not null.
11:57:10
Okay. If this is not the case, uh we will all all we need to do is just update the value of slow pointer and
11:57:17
fast pointer. So slow would be slow do next. So it will do one jump and fast
11:57:22
would be fast. Next do next
11:57:29
because fast pointer is actually doing two jumps. And once this loop ends, we simply need to return whatever the value
11:57:35
of slow uh list node is. And let's try to run this code.
11:57:41
Okay, seems like our solution is working. This is very few lines of code, so nothing to worry. Let's try try to
11:57:47
submit this. Okay, our code actually runs pretty fast. It's pretty efficient. So, I'll be
11:57:53
posting this in the comments. You can check it out from there. Also, I have created a GitHub repository where I have
11:57:59
posted uh the solution of all the problems that I have done so far. So, you can check it out over here as well.
11:58:04
Uh this is growing by the day. So, this would be helpful for a lot of people. I am I will be posting this link in the
11:58:10
comments as well.
11:58:18
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. Today we are going to do link list cycle problem. So
11:58:26
basically it is a problem to detect cycle inside the link list. And this problem has been asked by bunch of
11:58:31
different companies. So let's see that what are my dream companies that have asked this problem. Uh it contains the
11:58:37
companies like Amazon, Microsoft, Shopify, Goldman Sachs that we recently got rejected at.
11:58:43
Uh Google, Bloomberg, Apple, Facebook, Yahoo, Splunk, and eBay. So these are
11:58:51
some of the companies that I'm really interested to get a job into and uh that's why I'm paying my utmost
11:58:56
attention. I hope you also enjoy the video. So this is a lead code easy problem and
11:59:01
it is really simple to understand. Basically we are given the head of a link list and we need to determine that
11:59:07
whether this link list contains a cycle or not. Now first of all we need to understand that what is the property of a link list. Basically inside the link
11:59:14
list we are given two items. First item we are given some data point that represents that particular node inside
11:59:20
the link list and we are given the information about the next node inside the given link list and that is how link
11:59:27
list keeps on progressing. So we will keep this in mind like hopefully everyone should be uh familiar with this
11:59:33
one. And now the question is that we need to determine that whether inside our given link list does there exist a
11:59:41
loop or not. So suppose we are given a link list like this and we in this case
11:59:46
we can clearly see that there exist a loop between this four and this two. The question is that how do we detect that
11:59:53
there exist a cycle and uh first solution that comes to mind is the solution that we have been using a
11:59:58
different graph and uh some other problems. So basically what we can do is at any moment we are given this head
12:00:05
position. So what we can do is we can create another data structure uh called hash set and inside this hash set we are
12:00:14
going to keep track of all the visited nodes uh that we have passed so far. And
12:00:19
what we are going to do is initially first of all we are going to check that whether at any given node we are currently at if that exists inside this
12:00:26
v visited hashet or not. If it does not exist we will add it to this visited hashet and we will keep moving forward.
12:00:33
So at any moment if we encounter the same node we can clearly determine that there exist a cycle. So in this case
12:00:40
first of all we will check that whether this one exists in the visited hashet. It does not exist. So we will add one over here. Then again we check for two.
12:00:46
Two does not exist. So we will add two over here. Then again we check for three. Three does not exist. So again we add three over here. And again we check
12:00:53
for four. So four also does not exist. So we will add all four entries. Now from this four the next value it points
12:00:59
to it actually points to this value number two. And whenever we check that whether this two exist or not we can
12:01:05
clearly see that two exist over here. And we can immediately say that because we came back at a node that we have
12:01:11
already visited before inside the hashet. We can determine that there exist a cycle. And in this case we will
12:01:17
return true that okay yes there exists a cycle over here and uh that would be our solution. Now this solution is perfectly
12:01:24
fine. It works. Okay. If we calculate the time and space complexity the time complexity in this case is going to be
12:01:29
big of n because we are iterating over all the nodes just one one time. And the space complexity in this case would be
12:01:36
bigo of n as well because we are using this additional visited hash set uh to detect that whether there exist a cycle
12:01:43
or not. The next thing that your interviewer is going to do is he is clearly going to ask that solve this
12:01:49
problem without using this additional uh item additional space and the space
12:01:56
complexity should be big of one. So let me show you the most optimal solution where the space complexity would be big
12:02:02
of one and time complexity would be big of n. I have a short announcement. I have
12:02:08
recently created a GitHub repository. uh the link is in the description and I will quickly show it to you as well. So
12:02:14
this is the repository that I was talking about and I have left it public so anyone can access it. It contains
12:02:20
list of solutions of all the lead code problems that we have solved so far. Uh so you can click on any problem and you
12:02:26
can go to its solution and it will contain the Java solution for that particular problem that is acceptable at
12:02:31
lead code. Our aim is to see this list growing and uh I would be posting all
12:02:37
the solutions that I solve and uh hope it helps other fellow coders and uh our
12:02:42
aim is to get into fang and hopefully this can be a big stepping stone towards that direction.
12:02:52
Basically what we are going to do is we are actually going to have two pointers that iterate over this given link list.
12:02:59
And we are going to have a slow pointer and a fast pointer. And the aim is that
12:03:04
at any moment this fast pointer is always intended to stay ahead of the
12:03:09
slow pointer. And if we identify that this fast pointer actually reaches back
12:03:15
to the slow pointer, we can determine that there exists a cycle. Let me show you how. So what we are going to do is
12:03:21
we are at this head position. So we are going to first of all initialize our slow pointer and our fast pointer at
12:03:28
these positions. So uh slow pointer would be at the first position and fast pointer will always start at the second
12:03:34
position. Now we are at these position we are going to have one more condition that slow pointer will always do one
12:03:42
jump. So slow pointer will always do slow plus one. So it will always go to next node. But for the fast pointer we
12:03:49
are actually going to have fast pointer do two two jumps. So fast pointer is going to do fast pointer plus two nodes
12:03:56
two node jumps. And let's see that how things will turn out in this case. So initially we are at these positions. Now
12:04:02
this first pointer makes a makes two jumps and slow pointer makes one jump. So their corresponding position change.
12:04:09
So slow pointer will reach over here and meanwhile fast pointer actually made two jumps. So fast pointer will end up over
12:04:15
here. Now the in the next case the slow pointer again is going to make one jump.
12:04:22
So slow pointer will reach over here and this fast pointer is going to make two jumps. So fast pointer will make one
12:04:28
jump over here and second jump it will reach over here. So in this case fast pointer will also reach at this place
12:04:34
and slow pointer also reached at this place. So over here we determine that this value at this fast is equal to
12:04:41
value at the slow node. And because we identified this condition, this can only happen true if there existed a cycle
12:04:48
somewhere. And because there existed a cycle, we are able to determine that okay, there exist um like this fast and
12:04:55
slow reach at the same point. They met at the same node. So that's why there for sure there has to be a cycle. Uh
12:05:02
what happens if there does not exist a cycle? So say for an example in this case uh again let's just go back to this
12:05:09
scenario that okay this is the list list we are given and there does not exist a cycle and let's add one more node over
12:05:15
here we'll just uh name it number five and uh this is the whole link list we
12:05:21
are given. Now in this case again this is the slow pointer this is the fast pointer and we are always going to have
12:05:27
a terminating condition that either if slow reaches at the end or if fast
12:05:33
reaches at the end at any given moment we reach to the end of the list and we
12:05:38
find that the value of this slow or fast pointer is actually null. If that is the
12:05:43
case, we can determine that we are able to successfully traverse over the entire link list without detecting a cycle and
12:05:51
that would be our final solution. So in this case, uh slow is here, fast is here. Let's make one jump. So again, so
12:05:59
now the slow would be here and fast would actually be here. Now again, let's
12:06:04
just make one more jump. So in this case, uh slow would be here, but fast
12:06:10
would have already crossed this portion. So fast would be somewhere over here the node is null which means immediately we
12:06:16
can determine that because we find that the fast pointer was at null value that there does not exist a cycle in this
12:06:22
case and we can uh we will return false in this scenario. So this would be the
12:06:27
most optimal solution for this problem. It is very easy and very trivial to understand as long as you get this
12:06:33
trick. And if we calculate the time and space complexity, the time complexity would be big of n because in any case we
12:06:39
will have to iterate over all the nodes. In terms of space complexity apart from using couple of uh additional variables,
12:06:46
we are not using any more space. So we can say that the space complexity is actually constant time. We go off one
12:06:52
and this would be the most optimal approach. Okay. So first of all we are going to
12:06:57
check that if the given head is equal to null we are going to return false. So this would be an edge case that we took
12:07:03
care of. Now we are going to create two list nodes. Uh one is for slow and we
12:07:08
are going to initialize it to the head position and second one is fast and we
12:07:13
are going to initialize it to uh next pos uh the second position.
12:07:24
Okay. Now we are going to run a while loop that while slow is not equal to
12:07:29
null or uh fast is not equal to null. We are going to keep iterating over
12:07:40
and we are going to check that if the fast next element if that is null we can
12:07:45
also return false immediately. If that is not the case, if at any point we identify that the value at fast is equal
12:07:52
to value at slow. If that is the case, we can immediately say that there exists a cycle and we can return true.
12:08:01
Otherwise, we will have to update the counter. So slow would be slow. Next.
12:08:06
So because we are incrementing slow by one value. Uh but for fast, we are actually in incrementing fast by two
12:08:13
values. So fast would be fast.next.next. And uh that's it. And if at any moment
12:08:20
we are able to get out of the loop, we can always return false.
12:08:27
And uh this should be the solution. Let's try to run the code. Okay, seems like our solution is
12:08:33
working. Let's try to submit the code.
12:08:42
Oh, okay. We are going to check that if fast is equal to null
12:08:48
or fast next equal to null.
12:08:54
Okay, seems like our solution is working and it's actually pretty fast. It's actually uh it runs in 0 millisecond. So
12:09:00
100% faster than all the other solution. And even in terms of memory usage, we are beating out most of the people
12:09:06
because over here we are actually ending our loop early uh by using the these
12:09:12
both these conditions. And uh again inside the GitHub I will be providing
12:09:17
the solution to all these problems. So you can go and check it out over here. I will be posting this link in the
12:09:23
description and hope this video helps uh all the other communities that I feel so
12:09:28
dear for and uh not stopping till we get into fang. See you next.
12:09:40
Hello friends, we are still not employed by a fang company. So let's not stop late coding till we get there. Today we
12:09:45
are going to do a link list problem called merge to sorted list. So this problem has been asked in tech giants
12:09:51
like Amazon, Facebook, Microsoft, Apple, Uber, Google, uh Bloomberg, Bite Dance
12:09:57
which is Tik Tok and then companies like Yahoo, LinkedIn, Indeed and Roblox and
12:10:04
also IBM plus uh recently in news Twitter. So I am paying my utmost
12:10:10
attention. I hope you also enjoy the video.
12:10:16
This is a lead code easy problem and it is also one of the most liked problems on lead code. Uh if we understand the
12:10:22
problem statement, we are basically given the heads of two sorted link list uh list one and list two and we need to
12:10:30
merge these two link list in one single sorted list. So this is the important part that it has to be sorted and in the
12:10:37
end we need to return the head of the merge link list. Okay, let's try to understand this problem with an example.
12:10:44
So over here we are given two lists list one and list two. And we can see that both of them are increasing in ascending
12:10:49
order. And now we need to create a merge list from this. So this is the merge list that has been created. Even if you
12:10:56
observe the merge list, the ascending property is maintained. So which means that the merge list is also sorted. And
12:11:03
how it is sorted it basically it has taken values from whichever the nodes that had the smaller values. So in this
12:11:09
case these first two values were one one. So we can put any choose from any one right now this second. So and now we
12:11:16
are done with this value one and one over here now we need to take care of this two and three. So when we compare
12:11:22
this two and three we find that okay this value number two is actually smaller. So that's why we add a two node
12:11:28
over here. And now we are done with this one. And now we still have to compare this three with this four because
12:11:34
remember we are not done with this three yet. So we identify that this three is actually smaller. So in this case we are
12:11:39
done with this three and we add the three node over here in our merge list. Now the values are four and four. So
12:11:46
again we just enter the values four and four and now we should be done with all of them. And this is the new list that
12:11:51
we have created and in the answer we need to return the head value. So we would be returning this value as the
12:11:58
part of the answer. So this is the expectation of the problem. Let's see that what could be the potential solution. So let me draw quickly draw
12:12:05
just one more and we'll see that what should be the approach.
12:12:11
Let's see that what should be the merge list at the end. So I'm denoting this as m. Now uh we are going to compare two
12:12:19
values at any given moment and uh we are going to have two pointers. So let's say
12:12:24
left one and left two we are going to keep track of them. So over here both the values are same. So we can enter any
12:12:31
value. So we will add one over here. and then again one over here because both the values are same. So you can put
12:12:36
condition to choose anyone. Now we are done with both of them and because we are done with both of them we'll have to
12:12:42
update the values of this L1 and L2. So we are going to update its values. So
12:12:47
now this becomes our L1 and this becomes our L2. Again we do the comparison. Now in this case we find that okay this
12:12:54
value is actually smaller. So because this value is smaller we are done with this element essentially. We will add
12:13:00
that value to our merge list. And because in the list two we found that
12:13:05
that value was smaller, we'll update the list two pointer to go to its next element. So we'll do a jump like this.
12:13:11
And now this becomes our list two. And again we will compare list one and list two elements. So in this case we find
12:13:18
that value at list one is actually smaller. So we will add it to our solution. And uh again we are done with
12:13:25
this one now. So we'll update the po left one pointer. So left one pointer would fall over here. And now again we
12:13:33
will compare both of these values. So in this case we find that okay this value is actually smaller. So we will add one
12:13:39
more node to our merge list four. And again update the value of list two. So list two actually goes over here. And
12:13:46
this is done. So this is list two. And now we compare this value with this
12:13:52
value. So over here we would find that okay this five is actually smaller. So
12:13:58
now we will have to update the value five over here. Now because we have updated the value five over here, if we
12:14:03
do a next jump for this list one, we identify that this node is actually null. So the moment we identify that
12:14:10
there exist a null node, there is no point of us moving forward in this direction because we are done. And
12:14:16
essentially whatever the remaining values are still pending in the L2, they
12:14:22
directly needs to be appended on uh this merge list. Why? Because so far all the
12:14:28
elements we have entered they were entered based on the some sort of relative uh comparison but once we are
12:14:36
done with uh one loop there is nothing for us to compare. So because there is nothing for us to compare whatever is
12:14:42
the remaining portion we can directly add over here. So we'll uh over here we only have one node 8. So we'll directly
12:14:48
add the node 8 over here. But even if we had some other nodes over here they all would be directly appended without any
12:14:53
issues. I hope this makes sense. And this actually would be our final solution. Uh now what are what would be
12:15:00
the tricky part in this one? The tricky part in this one would be that because in this merge link list we are iterating
12:15:06
over here. So at the end we would be somewhere at the last position. And remember we need to return the head
12:15:13
node. So what we were what we will do is we are going to use a trick. We'll create some dummy node and this dummy
12:15:20
node would be actually as the head node. We will just assign some random value whatever 1 2 whatever this does not make
12:15:27
any difference and the next value of this would be pointing to the merge dot
12:15:33
next and that would be the trick. So at the end we will just return the next value of this dummy node and then that
12:15:41
would be the start point of our merge list. So if we calculate the time and space complexity in this case the time
12:15:46
complexity would be big of n actually because we have we will have to iterate
12:15:51
over all the nodes that are given in both list one and list two. So actually it would be big of m + n where m is the
12:15:59
total number of nodes given in list one and n is list two but in general we can write it as bigo of m + n. And in terms
12:16:07
of space complexity, we are only using couple of extra parameters to store the
12:16:12
value. And anyways, we will have to create this merge list. So we wouldn't consider that to be an additional space
12:16:18
being used. So we can say that we are actually solving this in constant time. And this would be the uh most optimal
12:16:25
solution. So first of all, we'll create a list
12:16:31
node and we will just call it as dummy. And uh for this dummy node actually we
12:16:37
are going to use this dummy node to keep track of the first element inside our merge list. Now we will create another
12:16:45
list node and we will call it as a merge list. So just let's just call it merge.
12:16:52
And we are actually going to initialize it with dummy value. And now uh we are going to run a while
12:17:00
loop. Now we are going to run a while loop up until the point that when we
12:17:05
have elements in both list one and list two. So at any point we encounter that
12:17:10
list one or list two either of them is empty we are going to uh break out of
12:17:16
this while loop and inside the while loop we will have to check that which one is a smaller value and suppose list
12:17:25
one is uh smaller than list two value. So in that case we will have to add it
12:17:30
to our merge list.
12:17:37
So now we will add uh the value to merge list but we are actually going to add it
12:17:43
to the next element inside the merge list and you will come to know that why we are doing it. So let's just do that.
12:17:51
And now we will also have to update the value of list one. So this should be list one. And now let's update the value
12:17:58
of list one.
12:18:03
Okay. And if that is not the case, which means that we will have to add the value from list two.
12:18:10
And after we break out from the loop, we will actually have to uh see that which
12:18:17
list still has values remaining because remember at any point we encounter null
12:18:23
in any either list one or list two, we break out of the loop. which means that there could be still uh more elements
12:18:29
that needs to be appended to this merge list and that should be taken from uh
12:18:35
whatever the list that is still not empty. So we will just put a condition
12:18:41
if list one is equal to null. If that is the case, we know that we will have to append the value of list two.
12:18:49
And if that is not the case, which means that list two is empty and list one still has elements. So we will add list
12:18:56
one to our merge list.
12:19:01
And once that is done uh we need to return the head of this merge uh link
12:19:07
list. But the problem is that now we are actually at the end of this merge list. So how can we get the head of this?
12:19:14
Well, actually we can get the head of this is by using this dummy node that we
12:19:19
created because remember that dummy is actually the start value of one and
12:19:25
dummy. Next would be the value of merge.next.
12:19:30
So that's why we actually have to create this additional node and uh in the
12:19:36
return we are actually going to return dummy dot head
12:19:42
and uh oh sorry dummy dot next
12:19:48
and this should give us the head value. So let's try to run this code.
12:19:56
Okay, looks like we made some mistake. Oh uh we are not uh we are not updating
12:20:03
the value of merge element because at every iteration the merge node also
12:20:09
needs to go to the next element because we are already adding a one value to this merge link list. So now let's try
12:20:16
to run the code. Okay, seems like our solution is working as expected. Let's submit this.
12:20:23
And our solution is actually 100% faster than all the other Java solutions. So
12:20:28
which is pretty good.
12:20:36
Hello friends, we are not employed by a fang company. So let's not stop lead code until we get there. Today we are going to do remove nth node from an end
12:20:42
of the list pro problem. And this problem can be asked in many different ways. And uh if we see the some of the
12:20:48
companies that have already asked this question, it's really nice. Uh so companies like Facebook, Amazon,
12:20:53
Microsoft, Google, Bloomberg, Uber, Apple, Bance, Goldman Sachs and
12:21:00
Salesforce they have all asked this problem and uh they are some of my dream companies that I want to work at. So
12:21:05
that's why I'm making these videos. I hope you enjoy them. Let's try to understand the problem
12:21:11
statement. This is a lead code medium problem and uh the title of the problem actually is self-explanatory
12:21:18
that essentially we are given the head of a link list and we need to remove the nth node from the end of the list and
12:21:26
then return its head. So this is the whole problem. If we try to understand it using an example in the example
12:21:33
originally we are given a list called 1 2 3 4 5 and over here we are given that
12:21:39
n is equal to 2. So we need to remove second node but remember we need to remove the second node or nth node from
12:21:46
the end of the list. So in this case this would be the first node at the end of the list and this would be the second
12:21:52
node at the end of the list. So we will need to remove this four and once we remove this four the answer would be
12:21:58
something like this. So this is what we need to return and uh in this case we will need to return this head pointer
12:22:04
and then automatically it will traverse towards the entire uh link list.
12:22:10
Okay. So let's see that what would be the most basic solution to solve this problem. Suppose we are given a custom example like this and we need to return
12:22:17
remove second node from the end of the list. Now in this case this would be the first node from the end of the list and
12:22:23
this would be the second node from the end of the list. So we know that we need to remove this value number five. Well thing is uh the we don't we are able to
12:22:30
know it because I have drawn in the picture over here and it is very evident to us but actually we don't know that
12:22:37
what is the length of this given list. So because we don't know the length what we need to do is that the answer is
12:22:43
quite simple. First we need to identify that what is the length and then we need to based on this given value n we will
12:22:48
need to determine that what is the element that we need to remove and then it becomes easy for us to remove the
12:22:53
element. Uh so what we are going to do is we are going to use a two pass approach and inside the first pass we
12:23:00
are just going to have a variable called n l and this l is to take care of the
12:23:06
length of this given link list. So in this case we would find that okay length is equal to six because there are six
12:23:11
node present in this given example. Now once we know that there are six node present and our given n is equal to two
12:23:17
we will need to remove the fifth node. Why fifth node? Because the node we need
12:23:23
to remove that is going to be determined based on the formula that total length minus whatever the n is given + one. Why
12:23:30
+ one? Because we are using one index uh calculation over here that this last element this uh sixth element is also
12:23:38
the first last element. Remember that this is the critical part that this is the first last element which means this
12:23:44
is the second last element. And because of that uh if we see over here that this
12:23:49
L is equal to 6. this n is equal to 2. So 6 - 2 + 1 is becomes 5. And that's
12:23:56
why we determine that we need to remove fifth node. If we don't do this + 1, essentially 6 - 2 would be four. And we
12:24:02
don't need to remove fourth node because fourth node is actually third node from the end of the list. So that is why I
12:24:08
gave you this long explanation. Now uh in the first pass we determined that okay this is the node we need to remove
12:24:14
that this fifth node we need to remove. So all we need to do is in the second node we uh in the second iteration we
12:24:20
are just going to iterate over this given list again till we reach the fifth node. So the moment we find that okay
12:24:26
our current node is fourth node which means that the next node is fifth node
12:24:32
right. So all we need to do is that whatever the fifth do next is pointing so currently fifth dot next is pointing
12:24:39
to this value number six we are going to append this value to this fourth dot next. So rather than over here this four
12:24:46
pointing to this five we are going to remove this link and we are going to make this four point to six which means
12:24:51
that this five is automatically removed from this given input list and that would be our solution. But the moment
12:24:58
you present the solution your interviewer is going to say that rather than using two pass system suppose we
12:25:03
want to complete this whole thing in just a single pass in just a single iteration then what should be your
12:25:09
approach and this is the critical part. So let me show you that what would be the most optimal solution.
12:25:18
Let's use the same example and inside the same example uh first let's try to understand couple of things over here.
12:25:24
Suppose over here in this case we are told that remove n is equal to 1. So how can we determine that n is equal to 1 is
12:25:31
which element? We can determine that okay this is the first element from the end of the list. Why? Because the very
12:25:39
next element of this one is actually null and this is the key point which means if we are given that n is equal to
12:25:45
two so which means we need to remove the second element from the end of the list. So how can we determine? We can determine it by saying that okay
12:25:52
currently if we are at this position the second node from this one. So next to
12:26:00
the next node would be a null node. And if that is true we can determine that okay this is the second node from the
12:26:05
end of the list. And this is a very important property that we need to identify. So basically what we are going
12:26:12
to do is we are going to use two pointer system over here. And inside the do pointer we are going to have a back
12:26:18
pointer and a front pointer. And the position of this back pointer and front pointer is determined based on whatever
12:26:26
this n is given. Say our if our back pointer is going to be at this position
12:26:31
which means our front pointer needs to be two steps ahead. So two steps ahead from this back position would be 1 2. So
12:26:37
this is where our front pointer would be at the beginning. Right? And now since
12:26:43
we have both of these positions set up uh all we need to do is just keep iterating to the next element and we are
12:26:49
going to iterate until we find that this f or the front element is actually at this null position. So let's see that
12:26:55
what would be the the uh different pointer situation. So now our back
12:27:01
pointer is come to this position and again our front pointer is going to come to this position because back pointer
12:27:07
jump from here to here and front pointer jump from here to here. Again we front
12:27:12
is not at null. So again we will have to do one more uh iteration. So now the
12:27:18
back pointer will come over here and the front pointer will jump to one more step
12:27:23
and front pointer will come over here. Again front is not null. So again our back pointer is going to take one more
12:27:30
jump and our front pointer is also going to take one more jump. So front pointer
12:27:35
will come over here and over here we've identified that this front pointer is at null position. So this is the critical
12:27:42
point. Now this front is at null position. So we have identified that okay now this back pointer is exactly uh
12:27:50
enough spaces behind it that the whatever the next node is that needs to
12:27:56
be removed and that is what we we are going to do. So over here we identify that okay this back is at current
12:28:03
correct position. Now what we need to do is currently back dot next is the point
12:28:09
that we need to remove. So what we are going to do is simply we are going to uh
12:28:14
point this current back dot next. So current back dot next is this file
12:28:20
value. We are going to point it to whatever the back do.ext dot next is and
12:28:26
this would be the solution because back what would be the back dot back uh next.ext it would be this one. So rather
12:28:33
than this four pointing to this five we are going to break this link which means that there is no way for us to reach to
12:28:39
this five. And now four is directly connecting to six. And then we need to return the solution. Now we need to
12:28:45
return the head of this link list. So we are going to use the same point. We are going we have been using so far that
12:28:52
initially we are going to create a dummy node. And this dummy node is going to act as a placeholder and that is going
12:28:58
to store this head value and we are going to return that in the solution. And uh let's see that what would be the
12:29:04
time and space complexity in this case. So for the time complexity it's only going to be big OO of L where L is the
12:29:11
given length of the link list and in terms of space complexity we are only storing couple of parameters. So it
12:29:17
would be constant time and so we are not using any additional space.
12:29:25
So first of all we are going to create a dummy node and uh inside this dummy node
12:29:31
we are going to give it some random value. We are going to create dummy dot next
12:29:37
equal to head and we are using this dummy node as a placeholder. Now let's
12:29:42
create our two front and back uh list nodes. Okay, once that is done, now we will
12:29:49
need to bring the front node n steps ahead of the back node. So we are going
12:29:54
to run a for loop. After this loop ends, the front and back
12:30:00
are at the current position. So now we only need to run a while loop till the front element is not equal to null. And
12:30:09
uh all we need to do is just increment the value of front and back elements.
12:30:15
And once that is done now we are at the correct position for back to remove the next node. So we are going to do back do
12:30:22
next equal to back next do next.
12:30:30
Okay. And now we have removed the node that the nth node from the end of the
12:30:35
list. So we can simply return the head of the list.
12:30:43
And this should be our solution. Let's try to run the code. Okay, seems like our code is working.
12:30:49
Let's try to submit the code. And our code runs pretty efficiently. I'll be
12:30:54
posting the solution in the comments so you can check it out from there. Thank you.
12:31:07
Today we are going to do a very interesting lead code problem called add two numbers. And if we see some of the
12:31:12
popular companies who have already asked this question, there are companies like Amazon, Apple, Bloomberg, Microsoft,
12:31:18
Facebook, Google, Uber, PTM, TCS, Bite Dance, Goldman Sachs and Airbnb. So
12:31:24
that's why I'm paying my utmost attention. I hope you also enjoy the video.
12:31:29
This one is a lead code medium problem and also very well-like problem. Basically, we are given two non-mpt link
12:31:35
list that represents two non- negative integers or two non- negative numbers.
12:31:41
Now, we are told that these digits are actually stored in a reverse order and we need to find the sum of these two
12:31:47
values. So, this is the whole problem. Basically, we are given just two numbers n1 and n2 and we need to find the sum of
12:31:54
them. So, n1 + n2 what is that going to be? And we need to uh the tricky part in this case is both of them are given in
12:32:00
form of like link list. So we are given link list one and link list two that represents both the numbers and we need
12:32:06
to add them and just create a answer link list and we need to return the head of this link list. So let's try to
12:32:12
understand this with an example and that would make things more clear. So suppose over here we are given two link list L1
12:32:18
and L2. Now notice that the numbers represent are over here are 2 43 and this one is 4 65. But we are told that
12:32:26
these are actually stored in the reverse order. Which means that the least significant number that in a number
12:32:32
system can be actually comes in the first position. Which means that the actually this one represents the number
12:32:38
342. If we want to put it in the decimal system, same way this one represents the
12:32:44
number 564. And now we need to do sum of these two values. And whatever the answer is, we
12:32:50
need to store it in a similar linkless kind of a fashion in reverse order. So the logic is going to be quite simple.
12:32:56
Let's try to understand this with an example. So basically in this case the two link list are 2, four and three. So
12:33:02
this one is link list one and link list two is going to be 4 6 and 5. Now if we
12:33:08
want to do sum of these two and store it in the result basically the answer is
12:33:13
going to look something like this. So first of all we are going to do sum of these two values 2 and four. So the answer is going to be six. We can put
12:33:20
six directly over here. Now in this case the value are four and six. So if we do 4 + 6 basically the answer we get is 10.
12:33:27
So 10 we cannot put directly as it is because we can only store one single
12:33:32
character in this kind of a block which means we can only store zero over here
12:33:37
and 1 is going to be a carry that will be forwarded over here. So let's just add one carry over here. So it's going
12:33:44
to be 1 + 3 + 5. So it's going to be 8. And the answer is basically uh 806. But
12:33:50
again since we have stored it in the link list fashion the answer has been stored reversely but the actual answer
12:33:56
is going to be 806 and basically this is what we need to return. So this is a
12:34:02
really simple problem to understand. So say for an example these are the two
12:34:08
numbers we are given. I'm also noting them over here uh 708 and 503 and we
12:34:14
need to do some of these one. What is going to be the most simple logic that we are going to use? Now given the fact
12:34:21
that we are given these two as link list one and link list two. The logic we are going to use is just a simple
12:34:27
arithmetic. Nothing more than that. The most basic approach that we have studied
12:34:32
in second grade. This is what we are going to do. We are just going to do simple arithmetic. So the idea is that
12:34:39
we are going to have a variable called carry that is going to keep track of that whether there is any carry that
12:34:44
exist or not for any single pair of sum that we are going to do. That is one thing. Second thing we need to iterate
12:34:51
over is uh until the possibility of whether we run out of both of these link list because it could be possible that
12:34:58
this link list could be only of length three and this link list could be of length four. We might have an additional
12:35:04
variable over here uh something like uh 6 and basically this value is going to be 653
12:35:11
but sum is going to be amongst these values and this value is going to be by itself. So we are only going to concern
12:35:17
about this value plus the carry in case we need to do it but since this is not the case we are not going to do it but
12:35:23
I'm just letting you know that these are the possibilities that could exist. Now we know till what points we need to run.
12:35:31
we know how to start and we know what are the values we need to do the sum of. So the logic is going to be that we are
12:35:38
simply going to create a new dummy node. So every single time we are going to create a new node. Now in this case I
12:35:44
know the answer is going to be this. So I I directly created this but typically it we will only be creating just one
12:35:50
dummy node okay at a time and then we would do sum of these two values and
12:35:56
initial carry value is going to be zero. So initially this carry value is going to be zero. Okay, now let me get rid of
12:36:02
these numbers. They are causing some confusion. So, first we are doing 8 + 3. 8 + 3 is going to be 11. Since 11 is
12:36:09
greater than 10, we are only going to put one over here. And we are going to change the value of the carry. Now, uh
12:36:15
carry can only have two values either zero or one. Why? Because the maximum possible number we can get amongst two
12:36:22
digits is always going to be 19. Why 19? Because uh the maximum two digits could
12:36:28
be 9 + 9. And we could have a previous carry that could be one. So even if we
12:36:33
do sum of all of these it could only lead lead up to the value of 19. So there can only be two possibilities for
12:36:40
the value of carry. So I'm just letting you know these things. Now uh in this case we have this value one. Okay. Now
12:36:47
we are going to move to the next value. So if we move to the next value basically this is 0 + 0. But the value
12:36:53
of carry is 1. So it's going to be 1 + 0 + 0. So the value is going to come one
12:36:58
over here. Now again in this case since we have already used this carry and we do not have anything the carry value is
12:37:05
going to go back to zero again. Now we have the value 7 + 5. 7 + 5 + 0. So that
12:37:10
is going to be value 12. But the 12 is still greater than 10. So we are only going to put two over here and we are
12:37:16
going to have a carry that we need to go over. And now notice in this case even
12:37:22
though we ran out of both of these uh link list and we do not have any more values to iterate over we still have
12:37:28
carry that is not zero. So again we are going to add one more node over here and
12:37:33
we are going to add the value of carry in this case and that is going to be one. So in this case the answer is going
12:37:39
to be 1 2 1 1 and this is like the numeric sequence if we go in this
12:37:45
direction but since we are only needed to return the link list we can simply return this link list as the answer and
12:37:51
this is the whole logic. So the problem is really simple to solve easy to understand and nothing more complicated.
12:37:58
Time complexity in this case the time complexity is basically going to be big go of maximum of either length of m or n
12:38:05
where m is the length of this one and n is the length of this one. So whichever is the maximum value we need to iterate
12:38:11
those many steps. So first of all we are going to create a
12:38:18
new list node called dummy node. This dummy node is going to act as a placeholder for our actual answer. Now
12:38:25
we are also going to create a new list node called answer. We are also going to have a variable called carry and the
12:38:31
initial value is going to be zero. Now we are going to run our y loop and inside our y loop we are going to keep
12:38:36
on running until we have values in either l1 or l2 or the value of carry is
12:38:41
not zero. Inside the loop first of all because these are list nodes we will
12:38:47
have to create two integer variables called x and y where we will store the value of the subsequent list one and
12:38:53
list two variables. if they are not null and if they are null we are going to store their values as zero. We're also
12:39:01
going to initialize a variable called sum and we are going to do x + y. We are going to calculate the value of carry.
12:39:07
So for that we can only do sum divided by 10 and we will get the answer. Now for our answer node we will have to add
12:39:15
the value of the sum that we have calculated. But it could be possible that the value of the sum could be greater than 10 and we only need to
12:39:22
store a single digit between 0 to 9. So what we can do is we can uh inside the
12:39:27
answer do next we can simply store the value of uh the sum modulo by 10. And
12:39:35
now for the present pointer we will need to update the pointer inside the answer list. So we are going to move to the
12:39:42
next element and same way we will also have to update the value of the L1 and L2 to move to the next nodes but we will
12:39:50
only do it if they are not null. Basically that's it. This is the whole meat of the operation. And now all we
12:39:57
need to do is we simply need to return the value of the dummy.next because dummy do.next points to the first value
12:40:04
where the answer node starts recording all the values. Let's try to run the code.
12:40:11
we are making a mistake. So inside the sum, we are not actually adding the value of the carry. So we will also have
12:40:17
to do that. Okay, seems like our solution is working. Let's submit this code. And our code runs decently
12:40:24
efficiently compared to a lot of other solutions. So this is a very good approach and I would be posting the
12:40:29
solution in the comments so you can check it out from there.
12:40:38
Hello friends, we are still not employed by a fang company. So let's not solve lead coding till we get there. Today we are going to do reorder list lead code
12:40:45
problem. And solving this one problem is actually equivalent to solving three different lead code problems. And I'll
12:40:51
show you how in this video. So if we check out the list of companies that have asked this problem uh there are
12:40:56
tech giants like Amazon, Microsoft, Adobe, Facebook, Bloomberg, Uber, Google, Yahoo, Apple, eBay, Lyft and
12:41:05
Expedia. And these are some of my dream companies. So that's why I'm making these videos. I hope you also enjoy the
12:41:10
video. So this is a lead code medium problem. And basically we are told that we are
12:41:15
given the head of a single link list and we need to reorder this link list and return in a different manner. So let me
12:41:22
quickly show you by an example that how do we want to return it. So suppose we are given a link list like this that 1 2
12:41:28
3 4. This is a normal link list we are given. And now we need to reorder it in
12:41:34
a manner that one node we take from this left to right direction and the another
12:41:39
node we take from this right to left direction. So in this case the first node is going to be this one. This node
12:41:46
number one. And now once we have taken this node from this left to right direction. The second node we are going
12:41:51
to take is from the opposite direction. So second node in this case is going to be this value number four. So second
12:41:56
node would be the value number four. Again since we are we have taken node from the end of the list. So next node
12:42:02
we are going to take would be this one the value number two. So again we will take a node this value number two. And
12:42:08
now uh at the end we will continue in the reverse fashion and the next node we will take would be value number three.
12:42:14
So this would so this is the sequence we would need to return in this case uh after all the nodes that we have taken.
12:42:22
Now let's take one more example. So again in this case we will iterate.
12:42:27
We will take one node from this left to right and one node from this right to left. So the first node would be node
12:42:33
number one. Uh second node would be node number five.
12:42:38
Then again next node would be node number two. Then again next node would be node number four. and then again uh
12:42:45
next node would be node number three. So in this case this would be the sequence
12:42:51
that we will need to return as the result. Suppose this is the link list we are
12:42:57
given and we need to uh reorder this link list. So what is the approach we are going to use? Basically we need to
12:43:03
understand that what are the things we need? Well we need the all the nodes that are going from left to right and we
12:43:08
are also need all the nodes that are coming from left to right. But the procritical part is that this is a
12:43:14
singly link list which means we don't have any way to move in the reverse order. So what we are going to do is
12:43:20
first of all we are going to create a reverse link list and then we are going to merge it with this original input and
12:43:28
the second link list we are creating we are going to create it smartly. So this is the input we are already given right.
12:43:34
So we already have our first link list that we need to create which is this one. Uh what we are going to do for the
12:43:40
second link list is for the second link list actually for this original given input first of all we are going to uh
12:43:47
find what that what is the middle of the link list. So in this case the middle of the link list is going to be this node
12:43:53
number four and the sequence starting from this node to 4 to 4 5 6 this is going to be the middle of the link list
12:43:59
right so in this case the first link list we have is and for the second link
12:44:04
list we are going to choose it from this middle node. So the second link list would be
12:44:12
okay. Now we have for both our link list first and second what we are going to do is we need all these nodes in the
12:44:20
reverse order. So we are going to uh for the second link list we are going to flip it in the reverse order. So now for
12:44:27
the second link list we are going to change it in the reverse order. So the second link list we will have would be like
12:44:36
okay okay and once this part is done for the third part we are going to merge
12:44:42
this first and second link list. So first of all let's see that what are the first and second link list we have.
12:44:49
Okay so this is the first and second link list we have. Uh we are going to merge two link list until the point when
12:44:56
we get the second node to reach to this null value. And how we are going to merge the list is that first we are
12:45:02
going to take the node from this first node. First link list then we will take the node from the second link list.
12:45:07
Again we will take a node from the first link list. Again we will take a node from the second link list. And we are going to keep iterating it until the
12:45:14
second reaches null. So let's see that in the action. So first node would come from the first link list. So this would
12:45:19
become our first node. Uh second node would come from the second link list. So this would become our second node. Again
12:45:24
we will repeat the same process. uh and in the end we would add this value
12:45:31
number four and then we realize that we have already reached to the null value for the second link list which means
12:45:36
that there are no other nodes to be added in the second link list which means we would stop adding even from
12:45:41
this first link list and we would not add the all the remaining entries and this would be our answer and we can
12:45:47
simply return this one. So this is the solution we are going to use and notice that in this solution we are actually
12:45:53
doing three different activities. So let's see that how to do each one of them.
12:45:58
First of all, we need to find the middle of the link list. And I have already solved this problem. So you can check out check out that particular solution
12:46:05
over here. Let me quickly go over the solution that I was I had already proposed.
12:46:12
So suppose I have a link list like this and if I wanted to do two partitions of it, all I'm going to do is I'm going to
12:46:18
create two pointers. One pointer is slow pointer and second pointer is fast pointer. For the slow pointer, it is
12:46:24
going to do one iteration uh to the next element. And for the fast pointer, we it
12:46:29
is going to do two hops to the next pointer. And whenever this fast pointer reaches to the end of the list, this
12:46:36
slow pointer would be at the middle position inside the given link list. So let me show you how. Initially the fast
12:46:43
pointer and slow pointer both would be at the same position. Uh then fast
12:46:48
pointer would take two jumps and slow pointer would take one jump. So fast pointer would reach over here and slow
12:46:53
pointer would reach over here. Again both of them are going to take subsequent jumps. So slow pointer would
12:46:59
reach over here and fast pointer would reach over here. Now again slow pointer
12:47:05
would take one more jump. So slow pointer would reach over here. But if fast pointer takes two jumps, we already
12:47:10
reach to the end of this list. Which means that whatever the position of this low pointer is, this is the uh part
12:47:16
where we need to do a partition and this would be the middle of the link list.
12:47:24
Next thing we need to do is that we will need to reverse the second link list. So suppose we are given a link list like
12:47:29
this. So I have already solved this problem as well. You can check out that solution over here.
12:47:36
And the idea is that we are going to have uh three two different pointers.
12:47:42
One pointer is previous pointer and second pointer is current pointer. And at any point we are going to have the
12:47:48
current pointer point to the previous element. So which means because this is a singly link list all the nodes are
12:47:54
pointing to the next element rather than them pointing towards next element. we are actually going to have uh any single
12:48:00
node point to its previous element and then this would become our head and then we we would have reversed the link list.
12:48:07
So let me quickly show you how initially we would have our current pointer over here and our previous pointer over here.
12:48:13
So now right now this current do next is pointing to the next element. Uh so
12:48:19
first of all we are going to create a temp variable and this in this temp variable we are going to store the value
12:48:24
of this current.next. So current do next we store. Okay. So temp variable is
12:48:29
currently over here. Now we are going to have this current variable which is pointing to this next element. Rather
12:48:36
than pointing it to next element, we are going to have it point to this previous element. So now this four rather than
12:48:42
pointing to this five, it is going to point to this previous element. So this would be null in this case. Okay. And
12:48:48
now once this is done, we are going to have this previous pointer jump to the current pointer. So now this previous
12:48:55
pointer would come over here. So this is the previous pointer because we have already updated the value of this value
12:49:01
number four. And then the current pointer we are going to take its value from this temp variable. So current
12:49:07
pointer would also end up over here. So this would also become the current pointer. Once we have this uh done now
12:49:14
in the next node we are going to repeat the same thing. So first of all this temp variable we are going to jump it to
12:49:19
the next element. So this uh so this would become the temp variable. Again
12:49:24
the for the current variable we are going to point it to the previous element. So now this file is going to
12:49:30
point to this node number four rather than pointing to this node number six. So we are breaking up this connection.
12:49:35
And then for the temp uh for the current variable we are going to flip it to this temp variable. So again current is going
12:49:41
to be ending up uh at this position. So this is where current is and this is
12:49:47
where temp is and then we will update the value of the previous node as well. So this is where the previous node is.
12:49:52
So once this is done again we will repeat the same process and then we will point when the previous element reaches
12:49:59
over here to the last node we are going to return this as the head. So in the
12:50:05
answer we would have reverse the original list. So we would have a so we would have a link list like this
12:50:14
and then once this is done all we need to do is now we we have two separate list we will need to merge them.
12:50:22
Okay. Uh so for the merge of two link list you can check out that solution over here. And let me quickly show you
12:50:28
here as well. We will start taking one node from each of the given list. And uh first node
12:50:36
would be node number one. Second node would be node number six. Then third node would be node number two. And next
12:50:42
node would be node number five. And then we will take node number three. And then we will take node number four from this
12:50:47
list. And now we realize that the second do next is actually null. Which means that now we don't need to take any more
12:50:53
nodes from any other link list. And we can whatever the answer is we can simply return this as our answer. And this
12:51:00
would be the final solution that we are going to use. So let's see that what would be the time and space complexity
12:51:05
in this case. So for the time complexity we are actually doing three different things. So first thing we are doing is
12:51:11
that we are actually splitting the link list in two parts. So that takes big go of n by two time plus second thing we
12:51:19
are doing is we are reversing the link list which takes big go of n time and third thing we are doing is we are merging two link list which take bigo of
12:51:26
n time. So in general we can say that we are doing big of n work and uh in terms
12:51:31
of space complexity we are actually using an additional uh link list this
12:51:37
second link list to store the values and over here we are actually storing like half of the nodes which means that we
12:51:43
need we will require big go of n by two additional space so generically we can
12:51:48
write this as big of n as well and this would be the time and space complexity let's see that what would be the implementation
12:51:58
First of all, we are going to check that whether the given head is equal to null. If that is the case, we can uh simply
12:52:03
return immediately. And if that is not the case, we will
12:52:09
start with our implementation. So first of all, we are actually going to uh find the middle of the link list. So let me
12:52:16
create two list nodes for that. Now once we have our slow and fast list
12:52:22
nodes, we are going to run a while loop that while either fast is equal to null or fast next equal to null, we will uh
12:52:30
move slow and fast pointer up until that point. Once this is done, uh we will have a new
12:52:38
link list uh starting from the slow end point and we will have to reverse that link list. So uh in order to reverse the
12:52:45
link list, we will need a previous node. So we will create a new list node called previous and we will assign it to the
12:52:52
value null. We will also have a current node and we can initialize it to uh the value of slope and we will have a
12:52:59
temporary uh node. Now uh we will run this loop while the
12:53:06
current is not equal to null. So first of all we will store the value
12:53:11
of current do next into temporary variable
12:53:20
and after that we will uh exchange the values of previous and current node. So
12:53:25
current do next will get the value of previous node and previous node will come at the
12:53:32
current node and current node we will need to move one step forward. So we will assign it to the temp node where we
12:53:40
initially store the value of the previous current dot next. And after this second loop runs, we should have
12:53:47
our second list, the slow list that we created to be reverse. And now all we
12:53:52
need to do is merge our first list and our second list. So let's create couple of list nodes. And we will create a list
12:53:59
node called first. and we will assign it to the value of
12:54:06
the head and we will also create a list node called uh second and we will assign it to the value of the previous node.
12:54:17
We will run a loop that while second do next is not equal to null.
12:54:22
So over here we will need to uh take the values from the second node and put it
12:54:28
behind the first node. So we are going to use the temporary variable for that. So first of all in the temporary
12:54:35
variable we are going to store the value of first.next
12:54:41
and after that for the first dot next value we will take a value from the
12:54:46
second node and for the first node we will get the
12:54:53
value of whatever the temp value we have we had already stored and after that is done we will repeat the same process for
12:54:59
the second node as well. So first of all we will create the temp to setup as second dot next
12:55:08
and then we will have second dot next
12:55:14
to point to the first node and in the end we will have second node
12:55:20
point to the temp node.
12:55:25
And once that is done, our code should be working as expected where we would have updated the value of this uh
12:55:32
original given list node. In this case, we don't have to return anything because the return type is void. We only need to
12:55:38
update whatever the given input is. So let's try to run the code. Okay, seems like our code is working as
12:55:44
expected. Let's submit the code. And our code is actually pretty efficient and it runs faster than most
12:55:51
of the other Java submissions. So which is pretty good thing to do. I would be posting this in the comments so you can
12:55:57
check it out from there. Also on the GitHub I have created a repository of all the questions that we have solved so
12:56:04
far. Uh and uh I have made it public so anyone can access it. I will be posting
12:56:09
this link in the comments as well. So you can check it out this link and it can be helpful to a lot of other people. So far we have around 60 to 70 questions
12:56:17
and uh we we are growing it by the day.
12:56:28
Hello friends, hope you're having a fantastic day today. So now once again we are going to do an awesomely lead
12:56:33
code popular I can't speak. So let's get started with the question. So the lead
12:56:39
code problem we are going to solve today is called find the duplicate number. We can see that this one is a medium
12:56:44
problem and also extremely well-like problem on lead code. The problem statement is quite simple. We are given
12:56:50
an array of integer called nums that contains n + 1 integers where each
12:56:55
integer is in the range of 1 to n. Now we are told that there is only one
12:57:01
repeated number in this nums array that we are given as the input. So we need to
12:57:06
find that what is that repeated number. On top of it to make things more
12:57:11
compelling we are given two conditions that we must solve the problem without modifying the existing array. So that is
12:57:18
option number one and second one is we must solve this using an constant extra space. So we don't want to use any other
12:57:24
data structure. So let's try to understand if this is the input we are given. Currently this input contains
12:57:29
seven element and we can see that in this case we are given values one up up until six. But the values there is one
12:57:37
value that is being repeated and that repeated value right here we can clearly see is value number four. So in this
12:57:44
case we need to return four as the answer that four is the repeated character that we have been able to
12:57:49
find. So really simple problem statement. Now let's quickly try to understand the brute force approach and
12:57:55
then we will build our solution on top of that.
12:58:00
So the brute force approach is actually very simple to understand. We can just simply create a new hash set and inside
12:58:06
this new hash set we will first check that whether the entry we are trying to iterating over if that is already
12:58:13
present inside the hash set. If that is the present that has to be the repeated element. If that is not the present we
12:58:18
can move on to the next element. So first we find value number six. It's not present. So we add it to six. Then we
12:58:24
find value number three. Once again we find value number one. Once again we find value number four and value number
12:58:29
two. So so far none of these values were present inside the hashet. So we added them. Next we identified value number
12:58:35
four. So four is already present inside the hashet and we can check that in big of one time which means because this is
12:58:42
already present. So in this case we can say for sure that four is the repeated
12:58:47
element. So this solution works well in big of end time which is great. But the issue is we are actually using an
12:58:53
additional data structure to store the value of this existing array. So this is
12:58:58
this is basically not allowed. So over here space complexity is going to be big of n. So this is not a good solution.
12:59:08
Let's try to see a better solution where we can actually make changes to the
12:59:13
existing array that we are already given. Once I know that we are not supposed to do that but this is one of
12:59:19
the way where we can find the solution very easily. The idea is that at any
12:59:24
single index position we try to go to its subsequent uh index value and keep
12:59:30
on repeating the same process. So eventually it should be able to lead us to the repeated person. So in this case
12:59:37
we can see that if we go to element number six um on the position number six we actually have value number five
12:59:43
located which means we are going to swap the values. So the value we are going to swap over here is that five would come
12:59:50
on this place and six would come on this place. So in this case we would have on position number zero element number five
12:59:57
located and so on and so forth. So we would keep on swapping the elements. So now this one will become six even
13:00:03
eventually this one will become four and this one will become uh four as well. So eventually we would be left with element
13:00:10
four hanging someplace. So the moment we identify that we can say for sure that four is the repeated character. Now the
13:00:17
problem with this approach is that in terms of swapping the elements we can actually complete this pro problem in go
13:00:24
of one space complexity but we would be actually modifying the input array. So this is also not a legitimate solution.
13:00:31
I mean the solution is legitimate. The other thing is if you can find this solution in any of your interviews the
13:00:37
interviewer would be more than likely to be happy with this this approach. But the thing is now we are we are trying to
13:00:44
find the most optimal solution without modifying the array
13:00:50
for that we are actually going to take use of a very popular technique that we
13:00:55
have seen in a link list. So in any particular link list whenever we had
13:01:00
repeated characters we actually were able to solve that whether we have a cycle inside the link list or not by
13:01:08
checking a very popular algorithm and that algorithm is uh called a tortoise
13:01:13
and hair algorithm where we simply take use of two pointers. one is a fast
13:01:19
pointer and the other one is a slow pointer and we iterate fast and slow pointer over the link list until the
13:01:26
fast pointer either reaches to the null value or we identify that fast pointer and slow pointer meet at some position.
13:01:32
So let me quickly go over the solution uh and then we will understand that how can we utilize that fact for our
13:01:39
approach. So the idea is that let's say that currently I have I'm given one
13:01:44
particular link list right and the values are quite straightforward. The thing is I realize that in this
13:01:50
particular link list this value number four once again points back to value number two. So which means in this case
13:01:56
I can actually point value number four back to value number two. So in a sense I can say that value number two is
13:02:03
actually present twice or it is the repeated element. Now I need to identify that whether there is a repeated element
13:02:09
or not. The idea in for a typical link list is that you start with a fast
13:02:14
pointer and slow pointer both at the same location. Fast pointer is going to do two jumps at a time. Meanwhile, slow
13:02:21
pointer is only going to do one jump at a time. So during the first iteration, fast pointer is going to end up over
13:02:27
here. During the second iteration, slow pointer is going to end up over here. Okay. Now we are going to keep on
13:02:33
repeating the same process. So during the next iteration fast pointer is going to go to four and once again go back to
13:02:38
two. So fast pointer is going to end up over here but meanwhile at the same time slow pointer is also going to make a
13:02:45
jump. So slow pointer will end up with one jump over here. During the next iteration fast pointer would end up over
13:02:51
here and at the same time slow pointer would also end up at the same position. So the moment we realize that fast both
13:02:58
fast and slow pointer are at the same position which means we can say for sure that there is a cycle inside this given
13:03:05
link list. So now the thing is this only confirms that there exist a cycle inside
13:03:10
the link list but we don't know for sure that what is the repeated element. So repeated element in this case is value
13:03:17
number two. But the thing is there is a very easy way to find that repeated element as well where we identify that
13:03:24
fast and slow pointer met at this particular position right uh at uh value
13:03:30
number four. So the thing is what we are actually going to do is that instead now
13:03:35
currently fast pointer is just going to stay inside the loop but we will need to have slow pointer to come outside the
13:03:42
loop somehow. So let's say that our slow pointer comes outside of the loop. It is right now over here and fast pointer is
13:03:48
now inside the loop. Now we are going to have fast pointer just hop one element and slow pointer also hop one element.
13:03:55
If we do that actually the funny thing is that mathematically the fast pointer
13:04:01
and slow pointer both would end up exactly where the repeated character
13:04:07
lies or exactly where we are able to identify the cycle. And we can see it over here and we are going to see it in
13:04:13
couple of other examples. So you can understand that my hypothesis in this scenario is correct. So now currently we
13:04:20
are only going to do one jumps because we have already identified the the element. Now in this case okay currently
13:04:26
this f is located over here. This slow pointer is located over here. If slow pointer makes one jump slow pointer
13:04:32
reaches over here. If fast pointer makes one jump fast pointer is going to end up over here. And this has to be the
13:04:38
repeated character because we identify both a slow and fast pointer ending up at the same place. So
13:04:45
now trust me this solution works. We will try to understand this with couple of examples. But first let's understand
13:04:51
that this solution was actually really good and simple that it worked for a link list. In the input we are actually
13:04:58
given an array. So how do we deal with this one? The idea is actually quite simple. uh and what I'm suggesting is
13:05:05
that instead of treating this whole array as set of an array, we are actually going to make use of the idea
13:05:12
of our second example where rather than swapping the values, we will just try to
13:05:18
create the links and how we are going to create the links based on so currently let's say that in this index number zero
13:05:25
this is the zero value. So we are going to treat it as node zero and this has value number six. So we are going to
13:05:31
assume that zero points to node number six. Then six has node number five. So
13:05:37
six points to node number five. And this using this logic we will try to visualize this as a linkless type of
13:05:45
variable. Okay. So let me just show you what I mean and then it would make much
13:05:50
more sense. So let's assume that okay currently we are at zero index. So
13:05:56
currently our zero index now it is pointing to index number six. Okay, index number six now in this case is
13:06:02
pointing to index number five. Five is once again pointing to four. Four is once again pointing to value number two.
13:06:09
Two is pointing to value number one. And one is once again pointing to value number three. And once again three is
13:06:15
pointing back to value number four. So rather than doing this, we can just say that three is pointing back to the value
13:06:22
number four. And in this case we know for a fact that four is the repeated character because this is where the the
13:06:29
cycle starts. So now let's just start running our algorithm. We are going to have our slow pointer and fast pointer
13:06:34
both start at the same position. Slow pointer is going to make one jump. Meanwhile fast pointer is going to make
13:06:40
two jumps. Once again repeatedly same thing is going to happen that fast pointer is going to make two jumps and
13:06:46
slow pointer is going to make one jump. So let's also quickly do that. So now currently we have our slow pointer over
13:06:52
here. Our fast pointer over here. Once again fast pointer makes two jumps. So fast pointer ends up over here. Slow
13:06:58
pointer ends up over here. Okay. Once again fast pointer is going to make two jumps. So now fast pointer is going to
13:07:05
cross inside the loop. So fast pointer would be one. This is would be the first jump and this would be the second jump.
13:07:11
So fast pointer is going to end up over here. Same way after making one jump slow pointer is also going to end up
13:07:16
over here. Which means we identified the place that both fast and slow pointer met. Okay. Now because fast and slow
13:07:24
pointer both met at this place, we know for sure that both fast and slow pointer are currently inside the loop. We will
13:07:30
have to find a way to break for value number or slow pointer outside the loop.
13:07:35
So we are actually going to start slow pointer at the beginning of the loop. And now we are simply going to do one
13:07:40
jump just like we saw inside the linkless example. So slow pointer will take one jump. Fast pointer will take
13:07:46
one jump. Once again slow pointer will take one jump and fast pointer will take one jump. And once again when slow
13:07:54
pointer takes one jump fast pointer will also end up at the same position and this index position has to be the
13:08:00
repeated character and we found the culprit that we were looking for. So this is the whole approach to solve this
13:08:07
problem. If you want you can take as many examples as you want. this distance
13:08:13
and where the place where both fast and slow pointer meets up uh distance from there to the starting pointer is always
13:08:19
going to remain same and this is going to allow us to find the duplicated item
13:08:24
without using constant without using extra space or without modifying the existing array. So this is a pretty good
13:08:31
equation to open up your mind and open the horizons of what can be different possibilities how can you start
13:08:38
understanding that what type of solutions can be there. So that's why this is pretty popular among top tier
13:08:44
companies. So if we see time complexity it's pretty obvious it's going to be big of n because we are simply going to
13:08:49
iterate over the given array like couple of times one to find the uh matching point and second one to find the the uh
13:08:57
duplicate number. Okay. and space complexity we know that this is going to be big of one and uh now let's quickly
13:09:03
see the coding solution for this one.
13:09:08
So the coding solution is actually quite simple and straightforward. Uh we are going to have our two variables fast
13:09:14
pointer and slow pointer initialize at the very first element. Then we are going to find the intersection between
13:09:20
two points. So we are going to run our while loop that while slow is not equal to fast and then we are going to have
13:09:26
slow pointer make one jump meanwhile fast pointer is going to make two jumps. Once that is done and we do find the
13:09:32
intersection now fast pointer is inside the cycle. So slow pointer we are going
13:09:37
to kick it out of the cycle by marking it initial position as zero. And then we
13:09:43
are simply going to check that while slow and fast are not the same. We are going to slow pointer iterate one step
13:09:48
and fast pointer also iterate one step. In the end we can simply return either slow or fast because both are at the
13:09:54
same position. So we will try to run this code.
13:10:01
Okay, seems like our solution is working. Let's submit this code. And our code runs extremely fast
13:10:08
compared to lot of other solutions. And it's especially difficult for a popular question like this. So yeah, you can
13:10:14
imagine once again the coding solution is going to be present inside our GitHub repository. So feel free to check it out
13:10:20
from there. Thank you.
13:10:31
So the problem we are going to solve today is called copy list with random pointer. And if you see some of the popular companies who have already asked
13:10:38
this question, there are companies like Amazon, Facebook, Bloomberg, Microsoft, Apple, Adobe, Google, Bite Dance, eBay
13:10:45
and Uber. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
13:10:54
This is a lead code medium problem and a very well-liked problem. Basically, in this problem, we are being asked to copy
13:11:00
a link list. The thing is this link list is actually kind of a tricky link list.
13:11:06
It's not your common link list. So if we know by a definition, the link list that
13:11:11
we understand has a structure that looks like this. And uh the last pointer
13:11:16
points to a null value. So this is a typical structure of a normal link list.
13:11:21
But the link list that we are given in this case is actually kind of little bit of tricky. It is a link list that looks
13:11:28
like a structure that is something like this. where in this structure we have the these two parts common. So uh the
13:11:36
green values over here are defined as the regular link list pointers where we
13:11:42
have a value and we also have a pointer that refers to the next item inside the link list. The thing is at times we are
13:11:50
also given these random pointers in our link list as well. And the purpose of these random pointers is that they can
13:11:56
point to anywhere and basically uh we need to keep track of all of this and on
13:12:04
whatever the given link list that we are we have been provided we need to create a deep copy of that particular link
13:12:12
list. So this is what is being asked in this problem. Like if you cannot find or
13:12:17
if you try to understand you can read this problem statement again uh by pausing the video right now or you can
13:12:23
see some examples that I have shown over here. So let's take a look at the first example. As I was mentioning that this
13:12:30
is not your typical common link list. You see in this link list we are given
13:12:35
one value for every single item. But thing is with this value rather than
13:12:40
having just a single pointer that points to the next element which is defined over here as this next pointer we are at
13:12:47
times also given this random pointer as well that can point to any direction and we need to keep track of that and we
13:12:55
need to create an exact copy. So inside the input we are only given the head of
13:13:01
the link list and uh this is the original link list structure behind the scenes and uh in the output based on
13:13:08
this given head value we need to iterate over this entire link list and after
13:13:13
iterating we need to create an exact copy of it. So the if we see some uh
13:13:18
structure of this given link list it is going to look somewhat like this.
13:13:24
So in the output basically we need to we are initially located at this position.
13:13:30
This is the head of the link list and we need to find a way to iterate over this
13:13:36
entire link list in the exact manner and create a deep copy. So what does a
13:13:42
creating a deep copy means? Means that if some node does not exist in our copy
13:13:48
then we would create a new node. Take all of these values exactly as mentioned and put these values inside our new node
13:13:56
and mark it as the uh node in our sequence and then in the end we need to return the newly created uh link list.
13:14:03
So basically we are going to create like five different nodes. uh every single node is going to look pretty much
13:14:10
similar to this and they are all going to have a structure that is common over here and basically we are going to
13:14:16
return this as the answer. So this is the whole ask. There are few other examples given as well but they are not
13:14:22
as important they are just kind of simple. So I think you get a general gist of what are the things are being
13:14:28
expected. Now we have already done similar questions like this and even say
13:14:34
for an example if this was just a random uh link list it would have been too easy
13:14:40
for us to solve this problem because we what we could have done is we initially
13:14:45
start with the first position. So with this head position and just keep on
13:14:51
creating a new link list based on whatever the values we are iterating over right now because we we have a very
13:14:59
certain path in any link list where the first node is the value. So we can just
13:15:05
copy whatever the value this has. So say for example this has value number five we can just copy this value as value
13:15:10
number five and this has value number six. We can also copy value number six. And if this has value number 10, we can
13:15:16
also copy value number 10. So these things are easy to do. It is also easy to iterate to the next node inside the
13:15:22
link list because we are directly given the pointer and using that we are also
13:15:27
going to do the same thing and basically in the end when we reach to the null value we have reached to the end and
13:15:34
simply we can return this as the answer. Now copying is not as simple in this
13:15:39
case because we are dealing with a structure that looks like this where there could be potential possibility of
13:15:47
cycle. What do I mean by potential possibility of cycle? Say for example, we are given these two nodes. The values
13:15:53
are 7 and 8. And we know for sure that this node is going to point over here and this node is going to point to the
13:15:59
null value. These two things are fact. But it could be possible that this these
13:16:04
two random nodes. So this random node points over here and this random node
13:16:10
points over here. Now if we try to iterate over this like a different version of this link list, what is going
13:16:18
to happen is that okay currently we are located at this head value. So what would happen in these cases? Well, the
13:16:24
thing that would happen in these cases is that over here rather than coming back to this point, we would from we
13:16:32
might end up creating a whole new node with the same value seven and we will
13:16:37
try to iterate over this value and this uh over here again for this particular seven the value is pointing towards
13:16:43
eight. So we might create a new node 8 and then we keep on repeating. So basically because there exist a cycle
13:16:50
over here we it is possible for us that while creating the copy we could end up
13:16:56
in an infinite loop and that could be disastrous. So we will have to avoid that in any single cost.
13:17:04
Okay. So say for an example this is one of the input that we are given and we are trying to convert this and trying to
13:17:09
create a deep copy of this. Basically we are given this as the head node right and now we need to iterate over this
13:17:16
one. Now but the thing is in this case if you see uh there is the cycle present
13:17:21
amongst these random nodes. So this is a cycle and if we don't take care of it we will actually keep on ending it in an
13:17:28
infinite loop. Now the thing is uh in order to detect any cycles we actually
13:17:33
have a great way of doing it in all the graph problems right but the thing is you would say that why am I mentioning
13:17:39
graph over here because clearly this has been shown as a list or a link list kind of a problem. The idea is that rather
13:17:47
than treating this as the linkless problem, we can actually treat this as a graph problem where uh every single
13:17:53
items can be treated as the form of vertices and edges because remember in the graph the two most important items
13:18:00
are vertices and edges. So for the vertices we can actually consider these input nodes of the link list as the
13:18:07
vertices. And for the edges we can actually consider uh these like next
13:18:13
edges. So the white edges and also these purple edges to be considered as the edges. Now in this case the edges are
13:18:19
going to be directed and also unweighted. Now after doing this after treating this
13:18:26
and trying to consider this as graph things becomes much easier for us to keep track. Why? Uh so I have actually
13:18:33
drawn this figure where I am visualizing this given input as a graph. Now in this
13:18:39
case if we treat this as a graph it becomes very easy for us to copy and maintain. Uh why? Because the logic we
13:18:47
can use in this case is that any single node we can actually create a visited directory or a hash set or a hash table
13:18:55
where we keep track of all the nodes that we have visited so far. So that way it is going to be great for us to keep
13:19:01
track of everything. And uh once we are done with all the nodes we can simply return the copied nodes. So the logic we
13:19:08
are going to use is okay let me make this little bit smaller. Okay. So now let's try to iterate over this given
13:19:14
node and we will start iterating through its head. So this is the head pointer and every single time we are going to
13:19:19
keep the same logic that we use in any single graph problem that first we will check that whether that particular node
13:19:25
has been visited or not. If it has been visited we will skip it. If it has not been visited we will add an entry over
13:19:31
here and we will create its clone node and we will keep on repeating the same process. Now for every single node we
13:19:37
have its edges. So basically we are going to go in depth per search manner
13:19:43
and in depth per search manner we are going to go over all the neighbors of any single node and keep on repeating
13:19:48
the same process. And also because we are repeatedly doing the same thing. We
13:19:53
are actually going to do this recursively. There is also an iterative way to doing it. But the thing is I like recursion better. So I'm just going to
13:20:00
show you the recursive way. But remember there is also an iterative way. And if we see this uh diagram basically there
13:20:06
are just few functionality. So these white edges they refer to the values of the next pointer and also these purple
13:20:13
edges they refer to the values of the random pointer. And uh let's start iterating. So first okay first we are at
13:20:20
this head pointer. So we are at this node number seven. Seven is not present inside our visited hashet. So first we
13:20:26
will add an entry seven over here. And now let's just create a new node called seven. So we will create a new node.
13:20:32
Okay. Seven has been created. Now what is the next node of the new node? This is the random pointer. So where the
13:20:38
random pointer is pointing towards, it is pointing towards null value. So if it is pointing towards the null value, we do not need to add it to our visited set
13:20:44
because remember null is not a new node but it's just like the end of the list.
13:20:49
So we'll just keep track of it. So okay, this one is like the null and also if we
13:20:55
see in this case the next pointer we need to go over is the next edge. So next as edge is pointing towards value
13:21:01
number 15. So we will check that whether 15 has been visited or not. 15 has not been visited. So we will add entry 15
13:21:07
over here. Now we will start visiting the 15's first edge which is the random pointer. So if we go depth for search
13:21:13
recursively. Okay. So this 15th uh random. So let's let me just create a new node 15 over here. And uh this 15th
13:21:22
random edge is taking towards node number 10. So 10 has not been visited. We will add an entry 10 over here. And
13:21:28
we will also create a new node for 10. And in this case uh the 10th next node
13:21:34
or the node in sequence is the random pointer. So random pointer is pointing towards 13. So 13 has not been visited.
13:21:41
So we will go over 13 node. So we will create a new entry called 13 over here in this case. Awesome. So now we have
13:21:47
all four of our nodes set up and we have also iterated towards the random pointers. So now at 13 when we iterate
13:21:54
over the random pointer of 13 it takes us back to the node number 15 and because this is taking us back to the
13:22:01
node number 15 which means we will check that okay whether this has been visited or not. Yes 15 has already been visited
13:22:07
which means we are in a cycle. So we we need to break out from there. So basically we do not care and we will not
13:22:15
get ourselves involved in this one because we have already created a copy of 15. So because we have created a copy
13:22:20
of 15 in this case. So rather than creating a new node for this particular random node, we will simply point it
13:22:27
towards this 15 that we had already created. And uh that is how everything
13:22:32
is going to work. And then uh we basically have taken care of this cycle
13:22:37
without getting secuded in the infinite loop because we use the visited hashet.
13:22:42
And then for every single node there is still the next node remaining that we need to traverse over which is simple to
13:22:49
do because for next node it is only pointing towards the next node. And in this case from 15 after completing this
13:22:55
sequence when we go to the next node okay this one is pointing towards value number 13. 13 we already created a new
13:23:01
node. So we do not need to create anything. We simply need to add the entry over here to point it towards the
13:23:06
correct direction. Same way 13 next node is going to be 10. That is also good. And in the end this 10 is going to point
13:23:13
towards the null value. And this is how our traversal is going to be completed. And we would have created an exact deep
13:23:20
copy of this particular link list with random pointers without doing any extra
13:23:25
work. And uh this is like a wonderful approach. So all we did is we treated
13:23:31
link list as graph and this is a great way to understand
13:23:37
that how can two different data structures can be interchanged and uh we can use trick of the one uh data
13:23:44
structure and the other data structure. So I know this was a little bit complicated to understand but if we just
13:23:50
like try to put some thought behind it uh things would make much more sense and uh if we see time and space complexity
13:23:57
in this case the time complexity is actually going to be bigger of v + e. So v + a is the number of vertices plus
13:24:04
edges. Why? Because uh this is a graph problem. So this is what we we have to
13:24:10
deal with. And uh in in general in this case rather than treating this as v plus
13:24:15
e we can actually treat it as big of n where n is the number of nodes given in the input. And in terms of space
13:24:22
complexity in order to use the recursion we will have to use big of n space. So
13:24:27
this is a decently good time in space complexity. Well uh I just need to make a quick remark. If we use the iterative
13:24:33
approach the space complexity would become big of one in that case.
13:24:41
First of all, we are going to create our visited hashmap. And inside our hashmap, uh we are actually going to do things a
13:24:48
little bit trickily. So as its key, we are going to keep the values of the old
13:24:53
node and as its subsequent value, we are going to keep the new copy newly
13:24:59
generated copy that we have created. So at any given moment we encounter any already visited node we can simply
13:25:05
return its copy rather than creating a new node every single time. So this copy random list method is also going to be
13:25:12
our recursive method. So first we will create a terminating edge case that if the given head is equal to null we can
13:25:18
simply return null. If that is not the case, first we will check that whether the current head value we are at has it
13:25:24
already been added to our visited node and if it has been visited we are simply
13:25:30
going to return the subsequent reference value that we have stored inside our visited node hashmap.
13:25:36
If say for an example this is has not been visited. So in that case we will
13:25:41
have to create a new node. Now as a new node we are assigning it to the value of the current head value that we have
13:25:47
received as an input and as its random pointer and next pointer current values are null but we are going to populate
13:25:54
these. Now once this has been done since this is a new node this needs to be put
13:26:00
inside our newly uh inside our hashmap. Now notice in this case the head is the
13:26:05
existing node that we are taking as an input and this node is the new node that we have created which means we are
13:26:12
storing the copy as the value inside our visited node hashmap and as a key we are
13:26:17
using the older value. So now for this particular node we have taken care of the value of that particular node but
13:26:23
thing is we haven't taken care of the next pointer and also the random pointer. So we will do that. In order to
13:26:30
do that, we will actually have to call the for the next pointer, we will actually have to call head dot next
13:26:36
value and we will have to call our recursive copy random list method again. So let's do that. And same way for the
13:26:43
random pointer, we will also have to uh do the same thing. Basically once this has been completed, we simply need to
13:26:50
return the node. Let's try to run this code. It seems like our solution is working as expected. Let's submit this
13:26:57
code. And our solution runs pretty efficiently in time complexity compared to a lot of other solutions. In terms of
13:27:02
space complexity, there can still be improvements made. Uh but I guess you can figure that out. I'll be posting the
13:27:08
solution in the comments so you can check it out from there. Thank you.
13:27:18
Hello friends, we noted by a fang company. So let's not stop late coding till we get there. Today we are going to do merge k sorted list problem and this
13:27:26
is one of the most asked link list problem and uh if you just see that the number of companies that have asked this
13:27:31
question is really huge. Uh there are companies like Facebook, Amazon, Microsoft, Google, Apple, Bite Dance, uh
13:27:38
LinkedIn, Bloomberg, Tik Tok and uh more companies like Uber, Goldman Sachs,
13:27:44
Lyft, Twitter, Yahoo, Wish, Plantier, Tesla, Roblox, Pinterest, Airbnb. So
13:27:52
these are my dream companies. So that's why I'm paying my utmost attention. I hope you also enjoy the video. This is a
13:27:58
lead code hard problem and it is one of the most liked problems on lead code. But in my opinion, this should have been a medium problem and I'll tell you why.
13:28:06
Now if we understand the problem statement, basically we are given k distinct link list and each link list is
13:28:13
sorted in ascending order. In the answer, we need to merge all the link list that are given in one single sorted
13:28:20
link list and then return that merge uh link list. So this problem is very
13:28:25
similar to a previous problem. We did merge two uh sorted list. So you can find that solution over here. And if we
13:28:33
see the example for this case, uh basically we are given bunch of different link list and all of them are
13:28:40
sorted. So uh if we see this first example we are given link list like now
13:28:46
we need to sort all of merge all of them in one single link list and that single link list needs to be sorted. So if we
13:28:53
see the answer the answer in this case is going to be that okay the smallest values are 1 one so they will always
13:29:00
come first. So it would be 1 one then we will have 2 3 4. So 2 3 4 4 and then we
13:29:09
will have five and six and this would be the answer that we need to return in this case that is the combination of all
13:29:15
three uh link list. Basically in the brute force what we can do is uh we are given few distinct
13:29:23
number of lists. So it could be like list one, list two, list three all the way up to list K. These are the list we
13:29:30
are given in the input. What we can do is whatever the number of nodes they have, we can take all of those nodes. We
13:29:37
can combine all the nodes. We can put it in a giant list. Let's just name it as merge list. In the merge list, initially
13:29:43
we put all the values together once. And then all we need to do is if we just
13:29:48
sort this given merge list, uh then the sorted list would be our answer. And
13:29:54
basically that's the that's the whole solution. This solution would work perfectly fine. And we then in the end
13:30:01
we can just return whatever the sorted list we have found. Uh okay what could be the issues with this problem like I I
13:30:08
won't find too many issues because this is also a decently good enough uh solution. If we see the time and space
13:30:14
complexity in this case the time complexity is going to be big of n log n. Why n login? because initially we
13:30:21
will have to do big of n work to iterate over all the nodes inside the given link
13:30:27
lists different link list and merge them together. Uh so that takes n of n time
13:30:32
and plus it takes of n log n time to sort the given uh list. So overall we
13:30:40
will write them as bigo of n log n and in terms of space complexity the space
13:30:46
complexity in this case is going to be bigo of n because we need additional room to space to store one additional
13:30:53
parameter uh of all the merge list before we sort it.
13:31:00
Let's see that what could be another solution. So in terms of the second solution uh suppose we are given three
13:31:06
different list like this. In this case k is equal to three because
13:31:11
we are given three distinct values. What we can do is at any point we can denote
13:31:17
three different pointers to each location. Let's name them L1, L2, L3.
13:31:23
And what we are going to do is our aim is to find the minimum value. We already know that for these three values all the
13:31:29
values are already in ascending order. So the approach that comes to mind is okay let's just create our merge list
13:31:36
and inside the merge list at any point we are going to compare all the values between this L1 L2 and L3 and whichever
13:31:42
is the smallest we are going to pick that one. So in this case okay the smallest value is one so we'll pick one
13:31:47
over here and then we will update the value of L1. Okay so this is already done. Uh L2 and L3 will still remain
13:31:54
same. So now we have these three values that we need to compare. So the smallest value is two. So again we will update
13:32:00
the L2 and uh this we are done. Uh so now we have these three values to
13:32:06
compare. So now again we'll add value number three and then we will be done with this one and we'll update the value
13:32:11
of L3. So let me just do it do the whole thing and uh hope you you would be able
13:32:18
to understand that what how am I doing it.
13:32:25
Okay. So this is how we will progress and this would be our final merge list. So we can simply return this one. So
13:32:31
this approach also works fine. Uh there is there are no issues with that. If we see the time and space complexity in
13:32:36
this one the time complexity actually becomes so suppose if we consider that all the elements in this L1, L2 and L3
13:32:43
the total number of nodes are given n. So we can say that the time complexity is going to be big of n times whatever
13:32:50
the this k is given. So in this case k is three. So we can do n * k. So it's
13:32:55
going to be n * k and this would be the time complexity. So why n * k because
13:33:00
remember in order for us to enter any single element we will have to do k work. We will have to compare all these
13:33:07
three elements and at any point we find the smallest element we will have to update that value. So suppose if k is
13:33:12
equal to 1,000 then we might have to compare 1,000 elements as at once. So that adds a little bit of complexity to
13:33:19
it. So is this approach good? uh this approach is okay but not very good because as I mentioned that if we are
13:33:26
given million elements as k then uh basically what we are doing is just big
13:33:31
of n square work while we already know that even in brute force we are able to solve this in big of n login so why do
13:33:38
we need to do n square work okay so there is no point in doing that uh let's see that what would be the most optimal
13:33:44
solution okay so suppose we are given three lists
13:33:50
like this and I know You are thinking that why I only put two elements in each list. I'll just show you why. Uh
13:33:56
basically what is our aim? Our aim is to find that all the nodes that should be
13:34:02
merged and that mergedness merge list has to be in ascending order. Right? We need to maintain this ascending order.
13:34:09
So one of the best thing that should come to your mind is that is there any data structure that already exist where
13:34:15
no matter how many number of elements you put inside it whenever you start taking the elements outside they should
13:34:22
be following this ascending order property and yes there exist a predefined element or data structure
13:34:28
that can do it and that name is actually heap. So if we maintain a min heap in
13:34:33
this case uh so the if we add all the values inside the min heap and then we
13:34:38
start taking values or the nodes outside of the min heap it is actually actually going to give us the sorted list uh
13:34:46
where it is the combination of all the merge elements. Let me show you how. So let's create a priority Q that will
13:34:52
represent this main heap. Okay. And now let's start adding
13:35:00
elements one by one. So first we will add four and seven. Okay. Next element is three. So the moment we need to enter
13:35:06
three, we will have the priority Q is going to fix by fix itself. So now it is
13:35:12
going to be 3 4 7. Okay. Now we need to enter 8. So 8 we can enter over here. Now this node we have to enter is one.
13:35:20
So again when we need to enter the one, the priority Q is going to adjust itself. So now the solution is going to
13:35:25
be 1 3. And the last node we need to enter is
13:35:31
11. So this we have all the elements inside our priority Q. And now because
13:35:37
we have this priority Q setup, what we can do is now we can start pulling all the values from the priority Q because
13:35:44
remember the property of priority Q is that all the value values are entered at
13:35:49
the back and they gets out from the front. Uh so now we will create a new
13:35:54
merge list. Now inside this new merge list all we need to do is just keep on adding all the elements that are coming
13:36:01
out of this priority queue. So sequentially we will be adding 1 3 4 7
13:36:07
and all those elements and this would be the final solution that we need to return and we can simply return this as
13:36:14
our answer and this would be the most optimal approach. Like this is there are other approaches that work in the same
13:36:21
time and space complexity. But why this would be an optimal approach because your interviewer would like to hear that
13:36:27
okay you are aware about this min heap concept and you can use priority q when needed. So this sounds reasonably fine.
13:36:34
If we see the time and space complexity in this case the time complexity is going to be big of n log n. Why n login?
13:36:41
because uh in order for us to enter all the values inside the priority q it takes a login time and uh we need to do
13:36:48
it for all the these n elements and in terms of space complexity the space
13:36:53
complexity is going to be big of n because we need to use this additional priority q and uh let's see the coding
13:37:01
so first of all we will initialize a priority q and uh let's name it min heap
13:37:08
so now we are going to run a for loop and we are going to iterate all the lists and all the nodes and we are going
13:37:14
to keep on adding those inside our min heap
13:37:20
and uh after adding the value to the min heap we will have to update the value of list as well. So we'll do list is equal
13:37:26
to list do next.
13:37:32
Okay. So after this loop ends uh all the nodes should be inside our uh main heap.
13:37:38
And now what we need to do is take all the elements out out of the min heap and put it inside our merge list. So first
13:37:44
of all we are going to create a dummy node uh that would act as a placeholder
13:37:50
for so that we can call uh our head when we when we need it. And this is the same trick we use in previous videos as well.
13:37:57
So you might be aware of it. Once this is done, we will create our uh
13:38:03
list node called merged list. And for the merge we are going to uh assign the
13:38:11
first value as dummy so that in the future we can call this dummy node to find the head of this merge list. And
13:38:17
now we simply need to run a loop that while there exist an element inside the
13:38:22
min heap we will have to add all those elements to our merge list.
13:38:30
And once this is done all we need to do is just return the dummy. Next.
13:38:39
And this should be our solution. Let's try to run the code. Okay. Seems like our solution is working
13:38:45
as expected. Let's submit the code. And our solution works pretty efficiently as you can see. And I would
13:38:52
be posting this solution inside the comments. So you can check it out from there. Thank you.
13:39:06
And my aim is to empower every single person to be better at technical interviews. Keeping with that goal in mind, today we are going to do a very
13:39:12
interesting lead code problem called reverse nodes in a K group. If we see some of the popular companies who have
13:39:18
already asked this question, there are companies like Amazon, Microsoft, Apple, Bloomberg, Google, Tik Tok, Facebook,
13:39:24
Bance, Uber, Snapchat, PTM and Tesla. So that's why I'm paying my utmost attention. I hope you also enjoy the
13:39:30
video. So this is a lead code hard problem and also very well-like problem on lead
13:39:36
code. Basically we are given the head of a link list and we are also given another value integer value called K.
13:39:42
Now based on this given head of the link list we need to reverse the nodes inside
13:39:47
the given link list K at a time and we need to return the modified list. There
13:39:53
are also some additional parameters given which states that basically if we have the number of nodes that are less
13:39:59
than k we do not need to reverse them. Let's try to understand this with an example. If we see in this case we are
13:40:05
given a link list and we are given the value k is equal to two. Now if we
13:40:11
understand the problem statement basically we need to reverse the nodes inside this given link list k times at a
13:40:18
time. So in this case two nodes are given. So we are going to reverse two nodes and then keep on repeating the
13:40:23
same process. So the idea is first we are going to reverse these two nodes. Whatever the answer is we will store
13:40:28
over here. Then we will reverse these two nodes and again we will store that answer over here. And since this one is
13:40:35
only one node and we are given the value k is equal to 2. We are not going to change anything over here. So if we see
13:40:42
the answer in this case basically if we just reverse these two nodes the reverse node is going to look like this 2 and
13:40:48
one. Then we have the nodes three and four which are the two next k nodes or
13:40:54
next two nodes. So again we are going to reverse them and since this is only the
13:40:59
single node we will not reverse them. So this is going to be the modified reverse list that we need to return as the
13:41:05
answer. If we see basically we are reversing k nodes at a time and at any
13:41:11
point we identify the nodes less than k we do not do anything.
13:41:18
Now the most basic thing we can do to solve this problem is first of all we need to check for the HK scenario. The
13:41:25
HK scenario is that if the given number of K is actually greater than the number of elements present inside our link
13:41:31
list. If that is the case basically we don't need to modify the given input link list and we can return the answer
13:41:38
as it is. Now why we can do it? Because the given K is equal to 6 and we are
13:41:43
being asked to reverse K nodes. But in this case since k is greater than the given number of nodes present there is
13:41:49
no way for us to reverse all six nodes which means we don't need to modify the answer as at all and we can simply
13:41:56
return as it is. Let now let's try to think about some logical scenarios. Suppose our given value is equal to k is
13:42:03
equal to 2 3 something like that. If that is the case what is the approach we will take? The approach is quite simple.
13:42:09
First we will take these two nodes. we will do the reversing function for all
13:42:14
the remaining ones. We will repeat the same process after we are done reversing these two elements which means first we
13:42:20
will do like a reversing function and then for all the other nodes. So currently this one would be pointing
13:42:27
towards this three. Now for this new newly created list we would be able to
13:42:34
repeat the same process. If we repeat the same process now this time we will reverse these two nodes and again if we
13:42:40
keep on repeating the same process we will only be left with just a single node where which only contains one value
13:42:46
which is again less than the value of k which means we don't need to change this portion. If we see logically this
13:42:53
becomes a very good candidate for a recursive approach. Why recursive approach? Because essentially every
13:43:00
single time first of all we were considering all of these five nodes uh to do like k= to 2. Once we are done
13:43:08
iterating these two nodes, we can get rid of them. And now our input shrinks to the three nodes. And then again we
13:43:15
will repeat the same process. And then again if we get rid of these two nodes, we only are left with just a single
13:43:21
node. And then we need to repeat the same process. Which means recursively this is going to be a very beautiful
13:43:27
approach to solve this problem. Now we already know the overall framework on how to solve this one. But one key
13:43:35
important piece of information missing is the reverse uh function that we need
13:43:40
to perform in order to perform the proper reverse function. First let's identify that what is the methodology we
13:43:46
are going to use. Okay. Now let's try to figure out that
13:43:51
if this is the given input link list we are given. We are simply trying to reverse this whole link list. We are not
13:43:58
currently considering about the K values because we already know the solution. So if we want to reverse this entire link
13:44:04
list, what is the approach we can take? Well, let's try to see that what are things we have. We currently have a head
13:44:10
pointer that points to the first value inside our link list. Now we since we
13:44:15
need to do the reverse link list. Basically the reverse link list is going to have a new head and this would be the
13:44:21
head of the reverse link list. So we will also first of all we need to create a new node called new head and initially
13:44:29
new head value is going to be null. So let's just create a new head. I'm going to mark it as NH and currently the value
13:44:36
is null. Okay. We will also need to find some way to iterate over the given input
13:44:42
existing link list. For that what we can do is we can create a pointer node and this pointer node we are going to
13:44:48
initially assign it to the value of the head pointer and then we will use the pointer node towards to move towards the
13:44:55
next values. So let's just create a new pointer node in this case. After creating these two values, we will need
13:45:02
to at any given position keep track of the next node because for the pointer
13:45:07
node, we will need to iterate to the next element. At the same time, using the pointer node, we are going to
13:45:13
manipulate the values of the new head variable because we are reversing the link list. So we will need to create a
13:45:19
new variable called next node. And initially the next node value currently is null. Just understand for the sake of
13:45:26
understanding that this is null. And now we don't need the head node. So after initial setup or initially setting up
13:45:32
everything, let's see that what would be the approach to reverse the given link list. Okay. Now first thing we are going
13:45:40
to do is since we need to keep track of the next node, we will first assign the value. So we will keep the next node to
13:45:46
be the pointer do next. Okay, we set up the value of next node to be
13:45:51
pointer.next. So at this position the next node is going to be here. Okay. Now
13:45:57
we also need to keep track of the value of pointer.next. But the thing is since now we are trying to reverse the link
13:46:04
list. Basically the pointer do next is going to point towards the new head. So
13:46:10
let's mark that. So pointer do next should move towards the new head. Okay.
13:46:17
So currently the new head value is null. Keep it that way for now. Now we need to
13:46:23
update the value of the new head. So for the new head is going to be the existing
13:46:28
pointer we are at. So existing pointer currently is one. So in this case the new head is going to be the value of
13:46:34
one. Okay. So let's just mark this value. So new head is going to be the existing pointer value. And in the end
13:46:41
we need to move move this pointer to the next element. How would we be able to do
13:46:46
it? Using this next node because we already updated the value of pointer.ext. So we will need to move for
13:46:53
the pointer to the next value which is going to be pointer is going to move to the next node. So n and this using these
13:47:01
steps we would be able to reverse this link list easily. So now after the first iteration this is the current setup we
13:47:08
have that new head is located at one. Currently the pointer is located over
13:47:13
here and new node is also here but during the next iteration the values
13:47:18
will be updated. So now let's update the values again. So now okay new node becomes to the next value. So this is
13:47:25
going to be our new node. Now at the same time pointer do next points to the new head. So currently this pointer two
13:47:32
is pointing towards three but rather than pointing towards three now this two is pointing towards one. So we are going
13:47:39
to have a configuration. So currently the new head value is one and we are going to have two point to the one. This
13:47:46
is the current logic we have. Okay. At the same time new head is now going to move towards pointer which means that
13:47:53
rather than new head having the value of one it is going to have the value of two. So let me write this in a little
13:48:00
bit separate manner. So if I do that basically currently the new head is
13:48:05
going to be the pointer value and the pointer do next we already define it to be the previous new node which is going
13:48:12
to be one. Okay. So now this is the setup we have and also now pointer moves to the next node. So next node is three.
13:48:18
So now pointer again moves to the next node. So pointer is here. Next node is
13:48:24
here. Again if we repeat the same iteration basically the next node is going to be pointer do next. So this is
13:48:30
going to be the next node. Now pointer do next is going to become the new head. So pointer.next is currently pointing
13:48:36
towards the uh value number two. Uh sorry value number four but rather than
13:48:42
pointing towards value number four pointer.next is now going to point towards value number two.
13:48:47
At the same time, new head is going to become pointer. So now let's just make this changes as well. Now in the end we
13:48:54
simply need to move pointer to the next element. So now pointer will move to the next element. And in the end if we
13:49:00
repeat the same process again basically the next node will end up at null and we
13:49:06
will have the new head to be value number four.
13:49:13
And since the next node is null we cannot do anything. So we can break out of the loop here and whatever the next
13:49:21
is we can simply return that but at the same time we reverse the given entire
13:49:27
link list and this solves more the major concern of our pro problem. So now we
13:49:33
already know that how to reverse nodes. Okay.
13:49:41
So after understanding all the small pieces now let's see that what would be the optimal solution basically for the
13:49:48
optimal solution we have two options. First option is that we use the recursive function and then things
13:49:54
becomes much easier for us. Basically we take these two elements we apply the recursive function where we basically
13:50:00
reverse them and after reversing we update our value and again repeat the same process for these three remaining
13:50:07
items. Again we reverse these two items and then we keep the last item and then basically using the recursion and the
13:50:14
reverse function we would be able to solve this problem quite easily. Now for the recursive approach if we see time
13:50:20
and space complexity basically the time complexity is going to be big of n because we need to iterate over the
13:50:25
given input uh twice. Why twice? Because first we need to check that whether for
13:50:31
the given input if the given value of K is greater than or not or less than or not and then secondly we need to do it
13:50:37
for the reversing the K nodes. If we see space complexity the space complexity is
13:50:42
going to be bigo of one where uh sorry bigo of n where we will use n space for
13:50:49
the recursive stack. So the next question your interviewer is going to ask you is that rather than using the
13:50:55
bigo of n space complexity can you solve this problem in big of one space complexity. So that is also very simple
13:51:02
to do. Basically all we need to do is that at any given position first we will
13:51:08
try to see that whether the given k elements exist or not. If they exist then we will simply reverse them and we
13:51:15
can simply use like couple of while loops and do this iteratively and iterative uh the logic is going to
13:51:23
remain the same but first we are only going to check that whether the number of k elements are present or not. If
13:51:29
they're present, we are going to simply apply our reverse function and after keep on reversing the values. Uh
13:51:35
eventually we would be able to find our answer as needed
13:51:40
and iteratively this is the answer we need to return. If we see time and space complexity in this case the time
13:51:46
complexity is actually going to be big of n and the space complexities in this case is going to be big of one. Now for
13:51:54
the coding solution part of this particular reverse nodes and kg group portion. Actually I made a blunder
13:51:59
before I recorded the whole uh video explaining the code but uh I forgot to
13:52:04
use my microphone and that's why I didn't record any any of the voice. Now I'm not going to do the whole thing
13:52:10
again. I'm I can just go through the code and then I'll post this code in the comments and also I can post this code
13:52:16
in the GitHub uh repository that I have created and provide links for both of them. So basically you would be able to
13:52:23
see the code. Now in this particular solution basically we are using the
13:52:28
iterative approach by which we will have a better space complexity and uh
13:52:34
definitely we need to we need a way to reverse a link list. So I'm creating a helper method that takes in any list
13:52:41
node as an input and a k value and return the reverse link list new head.
13:52:47
So this uh these are all the steps that we discussed in the uh explanation part
13:52:53
of the video and we keep on repeating the same process and this is just just the helper method. Okay. Now let's move
13:52:59
on to the main method. Now inside the main method first of all we are defining
13:53:04
few of the variables that we need to keep track of different things. So basically we have a variable pointer to
13:53:10
that will iterate over the given entire list. We are also keeping track of a k tail variable. And what this kale
13:53:18
variable does is that whenever we are done iterating like any set of k nodes
13:53:24
uh and we are planning to go to the next step. So if we see on the left side of the screen suppose we have done
13:53:30
iterating reversing this one and two node which means we still have nodes 3 four and five to process. So ktail would
13:53:37
be pointing towards this node number two and we would be able to do certain things with that uh that we will see
13:53:43
next in the code. Now first of all we are going to initialize a while loop that while the pointer is not equal to
13:53:49
null which means this is the loop that runs over entire given link list. Now
13:53:54
inside that first of all we have a counter and we also have pointer located at the head position.
13:54:00
We first check that whether uh the current count if that is less than K we
13:54:06
will move the pointer towards the next element and keep on updating the value of K. And now we would be at the
13:54:12
position if the count is equal to K which means we are at the position where uh currently we will need to reverse the
13:54:19
the nodes that are between those values. So say for an example initially count
13:54:25
would be zero at this value number one and count count would be two at this value number two and basically uh we
13:54:32
need to reverse like these two values. So we will use our reverse function and after in this condition is only there
13:54:39
for the first case scenario because if we see in the output the head is always going to be the reverse portion of first
13:54:46
k nodes all the other k nodes doesn't matter. So that is why this is to define that what is going to be the new head
13:54:53
value and then this checks that whether the kale if that is not equal to null.
13:54:59
If that is not equal to null which means that the ktail value is actually going
13:55:05
to the going to point to the new reverse node value and that is why we are using
13:55:10
the ktail variable and in the end we just update the kale pointer and also the head pointer and keep on iterating
13:55:17
the while loop. So basically using the combination of these two we are able to solve this problem and in the end we are
13:55:24
simply returning the new head. So we will check that if the given new head is equal to null if that this is the
13:55:30
scenario this will only happen if the given k is actually greater than the number of values present inside our uh
13:55:37
link list and in that case we simply need to return the old head and if the new head is not null we need to return
13:55:43
the new head value and this is the whole solution. I hope the solution makes sense. And now let's try to run this
13:55:50
code. So our solution seems to be working. Let's submit this code. And if
13:55:56
we submit this code, our solution actually runs 100% faster than all the other solution. And that is because the
13:56:01
runtime is actually 0 millisecond. And uh even if we see in terms of space complexity, this is really good. So this
13:56:08
is a very good solution. Uh again, I would be posting this in the comments. So you can check it out from there or
13:56:13
you can check it out from this GitHub.
13:56:24
My aim is to empower every single person to be better at technical interviews. Keeping with that goal in mind, today we
13:56:30
are going to do a very interesting lead code problem called flatten the binary tree to link list problem. And if we see
13:56:36
some of the popular companies who have already asked this question, there are companies like Amazon, Google, Facebook, Microsoft, Apple, Bloomberg, Uber,
13:56:43
Goldman Sachs, Bite Dance and Lyft. So that's why I'm paying my utmost attention. I hope you also enjoy the
13:56:49
video. So this is a lead code medium problem and also a very well-liked problem.
13:56:55
Basically, we are given the root of a binary tree and we need to flatten this tree into a single link list. Okay, so
13:57:02
this is the whole problem statement. Now the question is how do we actually flatten it in the link list and what are
13:57:08
the rules for it. So the first rule is that the link list should use the same tree node class where the right child
13:57:16
pointer points to the next node in the list and left child pointer is always null. So what does it mean by this
13:57:22
definition? Suppose we are given a tree or binary tree that looks like this in the example. Basically the link list
13:57:30
structure would look completely different. It would look something like this where all the nodes are always on
13:57:36
the right side and nothing or the left child is always going to be null. So it
13:57:41
is going to be a onesided tree basically. The second condition we are asked is that the link list should be in
13:57:49
the same order as a pre-order traversal for any binary tree. So the question is
13:57:54
what does a pre-order traversal means? Suppose this is the tree that we are given the input. If you want to do a
13:58:00
pre-order traversal, the rules for pre-order traversal is basically first we iterate over the root node, then we
13:58:07
iterate its left child and then we iterate its right child. So as long as the left child exist, we will keep going
13:58:14
in the left direction. Once left child is no longer existent, we will go in the go for the right child and always we
13:58:19
will first iterate the root child. If we do that, basically in this case the pre-order traversal is going to look
13:58:26
something like this. So first we are going to iterate to the root node. So root node is one. Okay. So first we are
13:58:31
going to visit one. Then again left child. So left is also two. So we will visit two. Then again left child three.
13:58:38
So again three. Now we do not have any more nodes below this one. This is null. So because this is null. Now we will see
13:58:45
that whether its root node any had any right nodes or not. And yes it does have a right node. So we will start visiting
13:58:52
the right nodes again. And then we will keep on repeating the same process. So now we have visited everything on the
13:58:57
left sub tree. So now we will start iterating on the right sub tree. So if we go over here now we will visit node
13:59:03
number five and then node number six. So this would be the pre-order traverser. Now the question is that for the given
13:59:10
input tree uh what should be the answer look like? So we have to consider a couple of items uh in order to generate
13:59:17
the answer. First one is that it has to be the pre-order traversal and then it it has to be like a one directional
13:59:22
tree. Okay. So uh keeping with both things in mind the tree structure in the
13:59:28
answer is going to look something like this where the first node is going to be one and then the second node is going to
13:59:34
be in the pre-order traversal two but two we are going to mark it on the right side. The next one is going to be three.
13:59:40
So again three is also going to be marked on the right side. And if we keep on repeating the same process, basically
13:59:45
this is the answer tree that we need to return that represents the flattened
13:59:51
binary tree uh that we are given as the input. So this is the binary tree and this is the linkless version of it and
13:59:58
that this has been flattened. Uh now in terms of like input and output basically the input for this one is going to be
14:00:05
something like this. So basically this is going to be the original input that we are given that
14:00:11
represents this binary tree and after flattening it uh the tree is going to look like this and we need to return an
14:00:18
output that looks like this. So basically this is the whole ask of the problem. Now let's see that what is the
14:00:23
approach we can take. Okay suppose this is the most basic
14:00:30
input or most basic binary tree we are given. Now in any tree problem what we
14:00:35
are going to do is we will try to see that what would be the solution for this one and then using a recursive approach
14:00:41
we can actually solve it for much bigger problems because that is common property in tree. If we see most basic structure
14:00:47
of a tree basically it has a root node. Uh this root node currently has a left child and it also has a right child.
14:00:54
Okay. So uh let's mark some values so it makes sense for us to understand. So this value is one, this is two and this
14:01:01
is three. Suppose these this is the given tree. Now if we want to flatten this one, we will have to keep track of
14:01:06
two items. First one is that it has to be the pre-order traversal. So pre-order traversal, we already know the value is
14:01:12
going to be 1 2 and three in this order. Second thing we have to keep track of it is that it has to be a flattened version
14:01:18
and everything in just one directional. Okay. So what does that mean? That structure has to look something like
14:01:24
this where all the three nodes are just the right child, nothing on the left child. Keeping with these two items in
14:01:29
mind, the answer in this case is going to look something like this. And notice in this case the root node remains the
14:01:36
same. This left child is come as the first right child of this root node. And
14:01:42
the right child of this root node or this node two becomes this node three.
14:01:47
So basically if we just see what are the actions we did uh in order to generate
14:01:53
this answer. First of all, we took this left child and currently this left child
14:01:59
does not have any children of its own. So there is no like uh left child over here or right child over here. Right?
14:02:05
But if we see in the answer currently for this left child or this node it has
14:02:12
a right node and that right node is whatever the previous roots right child
14:02:17
was. So what we did is first of all for the existing left child we uh had the
14:02:24
left child dot write so right child of this original left
14:02:31
child which was originally null because it does not have any values over here. So this value was originally null we
14:02:38
marked it as the root.right
14:02:43
and which we can see over here that in this case uh this root.right Right? This
14:02:48
is this right child. We mark it over here. Okay. So this is one thing we did. Second thing we did is in the answer
14:02:55
currently this root. This left node actually has some value over here. But
14:03:01
in the in the answer this left child is null. So we will also do that. So
14:03:06
currently this root.
14:03:12
Okay. That is also the second thing we did. What is the third thing we did? And the third thing we did is that currently
14:03:19
this root.right this value is pointing towards the right child but rather than pointing it towards the right child now
14:03:25
we are pointing it towards the left child which which we can see over here clearly. So the third thing we are doing
14:03:31
is that root.right that was originally pointing towards the right pointer now it is pointing towards
14:03:39
the left child. And that's it. That is the whole logic to solve this problem.
14:03:46
and how we have been able to generate this. Let's try to see it for a bigger version and we will keep on repeating
14:03:52
the same process these three items. So now we will try to apply these three rules for this given tree and this is
14:04:00
the original bigger version. So first of all we will recursively try to find a smaller subset. We will do these three
14:04:06
things and keep on repeating the same process until we find the full answer. So first uh if we start iterating from
14:04:13
this root element first of all what we can see is uh this is one of the
14:04:19
candidate for the left subchild where we can actually apply these three uh rules.
14:04:24
So let's apply that. So after applying these three rules basically uh for this
14:04:30
particular portion this 2 3 and four the answer is going to look like this 2 3
14:04:36
and four. And if we just mark it over here, we will get a tree structure that looks like this. Now in this case, now
14:04:43
this is the perfect candidate because we do not have a full sub sub tree. So basically we have this left sub portion,
14:04:50
we have this right sub portion, we have this root node and again we are going to apply the same logic. So if we apply the
14:04:56
same logic in this case again second recursive second recursion what we need to do is for this particular left node
14:05:03
basically we will need to see that what is the rightmost tail and the rightmost tail is four. So this four needs to
14:05:11
point over here and this one rather than pointing to this five on the right child
14:05:17
this needs to point over here and the left child is going to be null. So this
14:05:23
is all we need to do. So if we apply these three logic basically uh first of
14:05:29
all we are going to have a root node one as the right child we are going to point
14:05:35
over here rather than pointing towards this five. So if we point towards this portion we will get the values 2 3 and
14:05:43
four and if we see currently this four is now pointing towards this value
14:05:49
number five. So that we are going to mark mark over here and basically we are going to have values five and six in
14:05:56
this case and if we see the left portion is always going to be null for every single one of them and this is the
14:06:03
answer we need to return. I know I have not drawn this properly so let me just do it properly and this is the most
14:06:09
simplest approach. What we did is uh we first of all try to find the solution for a smaller subset. We find the base
14:06:17
cases and the rules. We applied those rules to a bigger case and we using recursion we are able to generate this
14:06:23
answer. And this is a very simple answer to understand. If we see time and space complexity in this case the time
14:06:29
complexity is actually going to be big of n. And if we see space complexity the space complexity is also going to be big
14:06:35
of n because for recursion it is going to need to store some runtime stack.
14:06:45
So first of all we are going to create a helper method that we can use as our recursive method. So let's just do that.
14:06:51
Now in this helper method first of all we will check that if the given node is null we can simply return null. Second
14:06:56
thing we can check is that if the given node is like a leaf node which means if it does not have any left and right
14:07:02
child then we can simply return that node as it is. Now we will have to find the leftmost tree node for any sub tree.
14:07:11
So we will have to create a new tree node called left tail and we are going to call the recursive function again and
14:07:18
same way we will also have to find the rightmost tail. So we will also do the same thing and we will call the
14:07:23
recursive function again. Now will come the meat of our logic. So first of all
14:07:29
we will check that if the left tail value is not null if it exist then we
14:07:34
will have to put those three conditions that we discussed earlier. First of all, for this left tail value, which means
14:07:41
the leftmost value of any sub tree, we are going to mark its right child to point towards the node.
14:07:49
Then for the existing node. We are actually going to point it towards the
14:07:54
node. And in the end, the node.left value that we currently have some value
14:08:00
pointing towards, we are going to mark it as null. Basically, that's it. Now in the end we need to return the right tail
14:08:06
or the rightmost element. So we are going to check that if the right tail is
14:08:12
equal to null then we need to return the left tail. If it is not null we will return the right tail. And now all we
14:08:19
need to do is from our main method we will have to call the flatten tree method with the first root node. Let's
14:08:26
try to run this code. Seems like our solution is working as expected. Let's submit this code.
14:08:33
And our code runs pretty efficiently compared to a lot of other solutions. So which is great. I will be posting this
14:08:39
solution in the comments so you can check it out from there. Thank you.
14:08:55
Hello friends. Hope you are having a fantastic day today. So now we are going to do a full course on stacks. They are
14:09:02
one of the fundamental data structures and I can guarantee you that after this course you would become a master in all
14:09:08
questions related to stacks. In this course we are going to learn what is stacks, what are the benefits, how to
14:09:14
implement it, when to use it, what is the time and space complexity of different operations characteristics and
14:09:19
we are going to do 10 most asked most like and most popular lead code problems
14:09:24
on stacks. So without any delay let's get started.
14:09:31
So stack is one of the fundamental data structures of computer science. This is a linear data structure and typically
14:09:38
stacks are implemented using some sort of list function. So it can be either array list or link list. But the thing
14:09:44
is stack is not just typical any single array or link list. This is a special kind of list that contains a very
14:09:51
specific property and that is called leo property that is called last in first
14:09:57
out. So how does a stack typically works is that inside the stack you always have
14:10:02
to work with the values that you are entering is always going to end up at the bottom of the stack and then if you
14:10:09
have to enter the next value it will remain at the top of the stack and you can only access the element that was
14:10:16
last entered inside the stack. So let's try to understand this with an example. Currently let's say that we have this an
14:10:22
empty stack. Now for this stack if we try to add value number one. So one is going to stay at the bottom of the
14:10:28
stack. And now for this stack then since it only contains one value if we have to
14:10:33
see that what is the element inside the stack it will return us the result as one. But let's say that we don't do that
14:10:40
and we try to add one more element. So if we add value number two, it is going to come on top of value number one. And
14:10:46
then we add value number three, we can add value number five, something something. Now the moment uh over here
14:10:52
we decide that I want to get one element out from the stack. So the moment we try
14:10:58
to do that we cannot directly access this element three or two or one. We will always have to access element
14:11:05
number five first and once we kick element number five out or pop element number five out then only we can reach
14:11:11
to element number three. Which means the last value that was entered inside the stack is going to remain at top of the
14:11:18
stack and that is the only value we can access in any any given moment inside the stack. And this special property of
14:11:25
LEO actually comes in very handy for some very specific operations. So before
14:11:30
learning that let's try to understand that what a typical stack looks like in real world.
14:11:37
You can think of a stack of books or a stack of plates. And both of these uh
14:11:43
simply un shows us that how does a typical stack works in the real life because if we have bunch of books stack
14:11:51
on top of each other then we can only access the book that is currently present at the top of the stack and then
14:11:57
we will start going bottom one by one. So same thing applies for the stack of plates as well. And this would be the
14:12:04
best way to understand that how does the memory is stored inside the stack and this is implemented using some sort of
14:12:10
list function. So inside the stack there are mainly
14:12:15
three operations that we have to worry about. First operation is called push operation. So push means that you are
14:12:22
entering some value inside the stack. Next operation is called pop operation.
14:12:28
Pop means that some value that is already present inside the stack, you are going to access or fetch that top
14:12:35
element outside of the stack and then that element will no longer be present inside the given stack. And last
14:12:41
operation is called peak operation. So in the peak it is very similar to pop
14:12:46
but you are not actually fetching the value out. You are simply seeing that what is the current value that resides
14:12:52
at that location. So let's try to understand. Currently our stack is empty. Let me push one value. So if I
14:12:57
try to push value number three then three is going to be populated inside the stack. Then I can also push value
14:13:04
number four. Then I can also push value number seven and so on and so forth. Now at this position I decided to do a pop
14:13:11
operation. So let me just simply do a pop operation. The moment I do that the seven is actually going to be kicked out
14:13:17
of the given stack and it is going to be returned as part of the answer. So now the seven is no longer present inside
14:13:24
the given stack and it is over here that we are able to be fetch. Uh if I do pop
14:13:29
operation one more time then we would have four also being popped as well. And then if I try to do a push operation
14:13:36
once again and try to add value number five, then five is going to be present over here. The moment I do peak
14:13:42
operation at this moment, then I'm only going to be seeing that there is value number five currently present at the top
14:13:48
of the given stack. But I would still keep or leave this five untouched inside
14:13:54
the stack. I only see that what is the value associated with the peak operation. And all of these three
14:14:00
operation actually operates in big of one time. So there is a special way we actually implement stack inside the list
14:14:08
and that allow us to fetch complete all of these three operations in big of one time. So now let's just take a quick
14:14:15
look at the implementation for any particular given stack.
14:14:21
So let's start implementing the stack class.
14:14:27
We are going to use an integer array list to implement our stack class. And now let's create a constructor to open
14:14:32
an instance of the array list. Now one by one we are going to implement
14:14:39
our three push, pop and peak method. So let's start with the push method.
14:14:48
So for the push method we are not returning anything. We are taking an item integer item as an input and we are
14:14:55
simply adding it to the array list instance that we have created.
14:15:00
Now for the pop method first we are going to check that if the given items list is not empty then we need to return
14:15:08
the very last element that was entered inside the stack or the last element that is currently present inside the
14:15:13
item and we need to remove that from the existing array list.
14:15:22
So here for the pop method we check that if the given list is not empty then we
14:15:27
remove the very last element that was answered entered inside our array list. If that is not the case and if the given
14:15:34
list is actually empty then we simply return the null value and same way let's try to implement the peak method where
14:15:41
it is going to be very similar to our pop method. The only difference is that
14:15:46
instead of removing the element, we simply need to get the value of that element and that's it. So now we have
14:15:53
implemented the three methods for our stack. Now let us also try to implement the is empty method.
14:16:01
So for the is empty method we are simply checking that if the given items array list if that is empty or not. And that's
14:16:08
it. This is the complete implementation of the stack class. Now let us try to implement a main method and also run
14:16:15
some operations on the given stack class. So now we have implemented our main method where we are initializing a
14:16:21
new stack. So first of all we are pushing three elements onto the stack. The values are 10, 20 and 30. Next we
14:16:28
are going to be peing that what is the top element inside the given stack. So this should return us the answer as 30
14:16:35
because that was the very last element that we entered inside the list. Then we are going to pop an element once again
14:16:41
that should also return the value 30 because that was the last element that was entered. And then once again if we
14:16:47
do the pop operation it should return value number 20. And in the end we are going to simply see the peak operation.
14:16:53
So that should return value number 10. So let's try to run this code.
14:17:01
We forgot to change the name. Let's try to run the code. So we can see that for the very first operation the top element
14:17:08
is 30. Then the popped element is 30. Then once again we pop element number 20. And in the end after that when we
14:17:15
check for the top operation we can see a value number 10. So this is how stack is actually implemented. But lucky for us
14:17:22
stack is actually provided as one of the default application and we actually don't have to implement the stack class
14:17:29
all the time. This was just simply for your information.
14:17:35
Now let's learn that what are some of the popular use cases that we can apply stack at and you by knowing these use
14:17:44
cases we would be able to quickly identify during our interview or any problem we are trying to solve to
14:17:49
realize that whether stack would be a good choice or not. So number one thing where you can think of using a stack is
14:17:56
for any time you have to do an undo type of functionality. So what does undo
14:18:01
functionality means? We know that inside our computer or browser we have the functionality where it keeps track of
14:18:08
every single step that we have gone over across any set of websites. And then if
14:18:13
we click the back side backspace button or if we do the undo button inside the software such as word or uh any other
14:18:21
PowerPoint or something like that it is able to trace our steps back and then put us back to the previous state. So
14:18:27
how it does it is that it actually uses stack to store that information. Let's try to understand this with an example.
14:18:34
Suppose we currently have an empty stack and I'm trying to open a new browser
14:18:39
session inside the Google Chrome. So the moment I first uh go inside the Google
14:18:45
Chrome, I have a new empty stack being created. Now inside the Google first of all I decide to go to the Facebook
14:18:51
website which means stack is going to mark that I visited the Facebook website right now. through Facebook I decide to
14:18:57
go to the X or Twitter website. So next it is going to put the value of X on top
14:19:02
of my stack. Then I decide to go to the Uber website. So once again the same
14:19:07
information is going to be recorded and so on and so forth. Now at this position of Uber I decide to click on the back
14:19:14
button or the undo button where I want to go back to the previous state. Simply
14:19:19
the browser is going to pop the element that I have entered at the very last. So
14:19:25
this is going to be taken out. Now I'm no longer at the Uber place and whatever value located over here, it is going to
14:19:31
do a peak operation and bring me back to the uh Twitter page that I was previously browsing. So this is a great
14:19:37
use case. Now you can understand that how this leo property last in first out property actually help us to solve a
14:19:45
real world problem. Few other important use cases that we can think of for stack is to have it in the backtracking
14:19:52
mechanism because how does a typically backtracking works is that let's try to understand this with a small example of
14:19:59
trees. So inside any given tree if you have to iterate over the tree you will have to understand that what was the
14:20:06
previous state that you were iterating over and have you visited all of its children or not. So let's assume that I
14:20:12
have currently this type of scenario and I'm trying to go in the depth first search fashion. Now I know that this was
14:20:18
supposed to be a course on stack but I'm just explain you explaining you some simple theorem to understand that how
14:20:24
stack can be used with different data structures as well. So in the depth first search we actually go in one
14:20:30
single direction and the moment we try to find some value if the value is found that is great if that is not found then
14:20:37
we have to do the backtrack and do the do the same operation for the remaining children or remaining leaves as well. So
14:20:44
let's try to do that. Let's say that we are trying to find this particular element and we are doing a simple depth
14:20:50
for search. So first we are going to we are at we are located at this position. So we are going to go to the left child
14:20:56
once again to the left child and once again to the left child. We did not find the element we were looking for. But the thing is there might be some path that
14:21:03
we haven't explored. So we are going to do the backtracking and through this backtracking now we are going to see
14:21:09
that hey are all the childrens of this particular node uh that I have tested?
14:21:14
No I haven't tested them. So I'm going to check one more. Once again I did not find what I was looking for. Once again
14:21:20
I'm going to do the backtrack and through here I Okay. Okay, so now I have tested both of his children which means
14:21:26
now I will need to do the backtrack operation once again and through here okay there are still some children that
14:21:31
I haven't tested. So I will go on the right and once again I will go on the left and I found the value that I was looking for and at every given moment a
14:21:39
stack is going to keep track of every single information that we were iterating over. So we can quickly
14:21:45
backtrack to the previous position that we haven't iterated over. Let's try to understand this with some examples. So
14:21:51
let's say that these values are A, B, C, D, E and this is F and I. Okay. Let's
14:21:57
say that this is I. So initially our stack is going to be empty. Then we are at position number A. Then we move to
14:22:04
the position number B. Then we move to the position number C. Then we move to the position number D. At D we realize
14:22:09
we cannot go any go further anymore. So we will pop D out and we will check that
14:22:15
have we explored every single possibility at the C? No, we haven't checked. So once again we are going to go to the value number E. So we are
14:22:22
going to add value number E over here. Once again we haven't checked all the possibilities uh sorry we check all the possibilities at E. Once again we come
14:22:28
back to the C. We check all the possibilities at C. So we are going to remove C as well. Now we are at this
14:22:34
position number B. So for at B we haven't checked F. So we will add F over here. From F we haven't checked I and we
14:22:40
are going to reach to the I and I was the item that we were looking for. So we found our answer. So we can simply say
14:22:46
say that yeah this element is present inside this tree and we were able to smoothly iterate over the entire tree
14:22:53
using backtracking because we had the stack that contained the last in first out property. So now you start to
14:23:00
understand that how specific or how important stack is. Let's try to understand one more use case that is
14:23:07
that at any given moment you want to identify that whether the given sequence of let's say brackets or parentheses are
14:23:15
they valid or are they in the correct order or not and doing this can very easily be done using stacks. How we can
14:23:22
simply have a logic that whenever we identify an opening parenthesis, we are simply going to add that value to the
14:23:28
stack and whenever we identify a closing parenthesis, we will remove that value from the stack and see that the value
14:23:35
removed does it contains the same type of parenthesis or not. So let's try to see the example in action and then you
14:23:42
would be able to understand what I'm talking about. So first we encounter a square opening bracket. So we are going to mark square opening brackets then
14:23:48
curly opening bracket and then a round round opening bracket. Okay. So now we took care of all of these three
14:23:54
elements. Now we are at this position and we encounter a closing bracket. Now the thing is in order for this sequence
14:24:00
to be valid the closing bracket has to be exactly the same the same way that
14:24:06
that was for this particular bracket. So let's try to do that. So let's say that we pop this element out and over here we
14:24:13
identify that for this circular closing bracket the value we popped out was also opening bracket which means this is a
14:24:19
good sequence. So we can move forward. So now we no longer have this value. Next we have a a curly closing bracket.
14:24:26
So for curly closing bracket we realized that the value we popped out was also curly opening bracket. So this is also
14:24:32
matching pair that is good. And in the end we found out that the last element is also a closing bracket that is square
14:24:38
closing bracket and the value we popped out was also a square closing bracket. So we found this pair which means this
14:24:44
pair of parentheses is valid. Now the question is this is really important whenever you are building IDE or
14:24:51
compilers. So things like IntelliJ, Eclipse or Jet Brains or bunch of other compilers they all use this formula or
14:24:58
the stacks to keep track of every single opening and closing bracket. Now imagine in this scenario that this last element
14:25:05
say for some some reason this one is a closing circular closing bracket. Now at
14:25:10
this moment we identified a circular closing bracket and we try to pop this element out and we identify that this
14:25:16
was actually a square opening bracket which means this was a mismatch. So if that is the case, we can simply get rid
14:25:23
of these uh these things saying that this was an invalid pair and that that
14:25:29
is how we can use stack to complete these type of operations and we can do
14:25:34
all sorts of like functional logic and all sorts of important fun stuff using stack. So that's why they remain so
14:25:41
popular in terms of technical interviews. And now we are going to go ahead with the 10 questions about stacks
14:25:49
that we talked about. Completing these 10 questions will give you the full exposure towards stacks. These are some
14:25:56
of the most popular, most liked and most problems. Uh in terms of technical interviews, all of them are really
14:26:02
popular lead code problems and they have been asked in interviews tons of time. So without any delay, let's get started.
14:26:09
Hello friends, we are still not employed by a fang company of lead coding till we get there. Today we are going to do valid parenthesis lead code problem and
14:26:16
this problem has been asked by some of the companies where I want to work at. There are companies like Amazon, LinkedIn, Facebook, Microsoft,
14:26:21
Bloomberg, Spotify, Adobe, Google, Apple, Uber, Tik Tok, Goldman Sachs,
14:26:27
Twitter, Netflix, Twitch, Tesla, Bite Dance, Lyft and Airbnb have all asked
14:26:32
this question. So that's why I'm paying my utmost attention. I hope you also enjoy the video. This is a lead code
14:26:38
easy problem and also one of the most liked problems on lead code. uh and that is because this problem actually solves
14:26:44
one of the very real life application where a compiler has to check that whether the code has valid parentheses
14:26:50
or not and so that's why a lot of companies like to ask this problem as an interview question. Uh if we understand
14:26:55
the problem basically we are given a string s that contains just these three types of parentheses opening parenthesis
14:27:01
and closing parenthesis and we need to determine that if the given input is actually a valid input or not. We are
14:27:07
also given the definition that what counts as a valid input that if the opening brackets are closed by the same
14:27:13
type of closing brackets and also we are told that the opening brackets must be closed in the correct order. So let's
14:27:19
try to understand this with some examples over here. I have drawn bunch of different potential examples and we
14:27:25
will see that if they are valid or not. So first of all if we see this example we know that we have two closing uh two
14:27:30
opening brackets and we have two closing brackets. We can consider this as a valid string. So I'm just noting it as
14:27:35
B. Now again in this case we have two different types of opening brackets and we have two different times types of
14:27:42
closing brackets. So this is also a valid string. Now in this case uh this is an opening bracket. This is an
14:27:47
opening bracket. We have corresponding closing brackets. Again we have opening and closing brackets and again we have
14:27:52
opening and closing brackets. So everything is in order and the same kind of brackets are opened and correct in proper shape and size. So we can
14:27:59
consider this also as a valid format. Now if we come to this example, this is
14:28:05
an opening bracket. This is also an opening bracket. But we only have a closing bracket for this original opening bracket. So we can consider this
14:28:11
as invalid option. So we get an idea why it is invalid. In this case we have three opening brackets and only one
14:28:17
closing bracket. So again this is an invalid uh string. And in this case actually if we see the number of opening
14:28:23
brackets and number of closing brackets they are actually same. So we have one opening bracket and one closing bracket. Again one opening bracket and one type
14:28:30
of closing bracket. But this is still invalid. Why it is invalid? Because this bracket this curly bracket is actually
14:28:37
opened before this particular round bracket. So that's why it has to be closed before this round bracket closes.
14:28:43
And in this case this round bracket actually closes first before this curly bracket is being closed. So this is very
14:28:49
important property that we will have to keep track of and that is why we are told that we need to keep track of the
14:28:54
order in which they are opened and closed and then only we can determine that whether they are valid or not. So
14:29:00
this is also an invalid uh formula. So let's see that what would be the potential solution. What? So let's start
14:29:08
from the very simple example and see that what would be the intuition behind building a solution. Suppose we are
14:29:14
given an example that looks like this where we are given all of the brackets that are of the same kind and we are
14:29:19
given some opening brackets and some closing brackets. Well, we can clearly see that this is a valid approach. And
14:29:24
how we can determine is that we can actually create a counter. And what this counter does is that any g at any given
14:29:31
moment we identify an opening bracket, we are actually going to increase the value in this counter. And at any given
14:29:36
moment, if we encounter a closing bracket, we are actually going to decrease the value in this counter. And at the end, we have to check that
14:29:42
whether the value inside this counter if that is equal to zero. Which means we can determine that the same number of opening bracket and closing brackets are
14:29:48
present. And then we can say that the string is actually valid. If that is not the case, we can say it is invalid. So
14:29:53
if we see that in action, first of all, we have three opening brackets. So we will increment the value of this counter
14:29:58
three times. And if we do that, we will get the counter value to be at three. Again, now we identify a closing bracket. So now this value from three
14:30:05
becomes two. Again we identify two more closing brackets. So again it go it gets decreased two more times and then we get
14:30:12
the final counter value to be zero. And because we get this value as zero, we can say that okay this string is
14:30:18
actually valid string and the same number of opening and closing brackets are happening. So this is one way to
14:30:25
identify a solution. But in this case the complexity is actually very simple. Why? Because we are only using one kind
14:30:30
of opening and closing brackets. In our original problem we problem we are actually told that there are three
14:30:37
different kinds of opening and closing brackets and we will have to keep track of them. Also we need to keep track that
14:30:43
in what order they were opened and closed and that order also has to be maintained. So it is not just as simple
14:30:49
as keeping track of counter that we create three different counters for all single type one of them and then we see
14:30:55
that at the end whether this value is zero or not. We also have to keep track of that what is the order they were
14:31:00
opened in and they were closed in. For the optimal solution we know we need to take care of two things. First thing is
14:31:06
we need to check that whether the opening and closing number of brackets are same for each three different types
14:31:11
of parentheses or not. Second thing we have to take care is that what is the order in which they are opened and
14:31:17
closed. So first let's tackle the first problem. We know that for every single opening bracket there has to be a
14:31:22
closing bracket and they are always in pair. So now to quickly look them up we are actually going to use a hashmap.
14:31:28
Now inside our hashmap we are actually going to have all of these closing brackets as the keys and their opening
14:31:34
brackets as corresponding values. So we are going to have three entries. Now we have to take take care of their
14:31:40
order and number of occurrences. So the idea is we are actually going to use another data structure called stack and
14:31:47
the stack is actually going to be very helpful to us. So let's try to understand this with an example that how
14:31:53
we are going to use a stack over here. Suppose we are given an input that looks like this. Okay. Okay. So I'm going to
14:31:58
show you two examples um on how we are going to solve this problem. So first let's take this example and the idea is
14:32:04
that at any given moment we identify an open bracket we are going to add that value inside our stack and at any moment
14:32:10
we are go and going to encounter a closing bracket we are going to pop a value on from the stack and then we are
14:32:16
going to see that the whatever the value we popped out if that is the same value that is for any given uh hashmap value
14:32:24
we have inside the string for this that particular closing bracket. So let's see that in the action. First of all, we
14:32:30
identify these three opening brackets. So, we are going to add all of the entries inside our ST. So, first we will add a curly bracket. Then we will add uh
14:32:36
these two brackets. Once we are done with this one, now we have a closing bracket overhead. The moment we identify
14:32:41
a closing bracket, remember we will have to pop the value out of our stack. So, we are going to pop the value out of the stack. And the value we have popped out
14:32:47
is actually this one. Now, for this closing bracket, we are going to see that what is the value of that bracket
14:32:53
inside our hashmap. And the value of that bracket is also like this. And we are going to compare these two elements
14:33:00
that whatever we took out from the stack and whatever we got from this hashmap and both are same. So because both are same we can say that okay we are good so
14:33:06
far. And now so far we have actually taken care of these four elements and now we are gone this element. Again this
14:33:13
is also a closing bracket. So because this is also closing bracket we will have to pop a value out and we are going if we pop a value out we will get a
14:33:19
value that looks like this where that we arrived from our stack. And now we are going to check that for this particular
14:33:25
bracket that we were iterating over what is the corresponding value inside the hashmap. So the key is this one and the
14:33:31
corresponding value is this one. So the value we found from our hashmap is also this one and they both are same. So
14:33:37
because they both are same we can say that okay we are good up until this point. Now we are iterating over this curly bracket. So we again pop and also
14:33:44
I have forgot to delete this value. Now again we pop out a value from our stack. So now we don't have this value over
14:33:51
here and we have a bracket that looks like this. Again for this closing bracket the value inside our hashmap is also an opening curly bracket and both
14:33:57
are same. So we are good up until this point. Now we are only up to last two characters. So this is also an opening
14:34:03
bracket. The moment we identify opening bracket we will add an entry to our stack. And now this is a closing
14:34:08
bracket. So again we will pop this entry out. After popping this entry out, so this is the value we popped out from the
14:34:14
stack. And then we will compare from our hashmap. So the value is this one and both are same. So we are now we are at
14:34:20
the end of our string and because we are at the end of our string we are going to check that whether inside the stack we have entry any entry or not. We don't
14:34:26
have any entry. So we can return true in this case and we can say that the given string is actually valid and this would
14:34:33
be the answer. Now uh let's take one more example where the string is not valid and see that what we are going to
14:34:38
encounter in this case. Suppose we are given a string that looks like this. So in this case we have two opening
14:34:44
brackets and one closing bracket. So first of all we identify that this is the opening bracket. Uh we are going to
14:34:50
add an entry over here. Again we encounter an opening bracket. We are going to add an entry over here. Now we
14:34:55
encounter a closing bracket. The moment we encounter closing bracket we are actually going to pop out the value from our stack. And the value we popped out
14:35:02
is actually a curly opening bracket. Now for this closing bracket uh we actually have a corresponding value inside our
14:35:08
hashmap that looks like this one. Now these two are actually not same. So the moment we identify that these two are
14:35:14
not same, we can immediately return that this string is actually invalid and the parentheses are not in correct order. So
14:35:21
we we are done with this one. Time complexity is actually going to be bigo of n where the n is the number of
14:35:27
entries present inside the string and even in terms of space complexity because we are using a stack and hashmap. But we don't care about hashmap
14:35:33
because it has finite number of uh entries. But for the stack the values will be dependent on big go of n as well
14:35:40
on the number of in entries present inside the string. Now let's move on to coding.
14:35:48
So first of all we are going to initialize our hashmap and inside the hashmap we are going to store the values
14:35:54
for three different brackets that we are given. Okay we are done with this one. Now we
14:36:00
are going to initialize our stack and we are going to name it as stack as well. And now we are going to run a for loop
14:36:06
across the given string. So first of all we are going to initialize the character C and that is
14:36:12
to keep track of whatever the character we are looking over inside the given string. Now we are going to check that
14:36:18
if the current bracket is opening bracket or closing bracket which means that if the key value is present inside
14:36:24
this mapping bracket then we can define that it is a closing bracket. If not then we can define it as an opening
14:36:30
bracket. So if the value is not present inside this mapped bracket cre
14:36:36
which means that we will have to push the current value inside the stack. If
14:36:42
not which means that the value is actually closing bracket and then first of all we are going to pop the value out
14:36:48
of our uh stack and then we are going to compare it with whatever the value pair inside the map bracket we have and if
14:36:55
the stack is empty we can return false immediately. So in the else condition we check that
14:37:00
if the stack is empty we can return false immediately. If not we are going to pop out of the pop out a value from
14:37:07
the stack and we are going to name it as top element. And now we are going to check that whether that is the same
14:37:12
value that is present for the map bracket value key. And if the values are not same we can return false immediately
14:37:18
as well. And if that is not the case eventually if we get out of the loop then we will have to check that whether
14:37:24
the given stack is empty or not. If the stack is empty, we can return true or else we can return false.
14:37:30
Let's try to run this code. Okay, seems like our code is working as
14:37:35
expected. Let's submit the code. And our solution is actually pretty fast
14:37:40
compared to a lot of other solutions. Uh so I would be posting this in the comments so you can check it out from there. Thank you.
14:37:53
Hello friends. Hope you are having a fantastic day today. So once again we are going to do a very popular lead code
14:37:58
problem that has been asked in companies like Facebook, Amazon, Microsoft, Google, Apple and bunch of more. So
14:38:03
without any delay let's get started. So the lead code problem we are going to solve is called min stack and you can
14:38:09
see that this is a lead code medium problem and also a very well-like problem on lead code. The problem
14:38:14
statement is very simple that we need to design a stack that can support push, pop, top and retrieving the minimum
14:38:21
element inside the given stop. these four operations and it needs to run in constant time or big of one time. So we
14:38:29
need to implement the minstack class and these are all the methods that we need to implement. Now we know that how does
14:38:34
a typical stack work. Stack operates in leo principle last in first out. If we decide to push element number three then
14:38:41
we will have an entry three presented inside the stack. Next we can push another entry called one then once again
14:38:47
we will have entry called one. Then once again we can have push another entry called five. So currently we have three
14:38:53
elements. Now inside the stack if we have to pop this element then the element five would pop out. So let's
14:39:00
quickly pop one element. So then we will get answer number five. Then if we do pop once again we will have value number
14:39:07
one. After doing that if we were to add two two more elements or push two more
14:39:12
elements. Let's assume two and six. So once again we will have elements 2 and six. Something like this. Then if we do
14:39:18
top operation at this moment it it should return answer six because that is the top element inside the array. And
14:39:24
then if we do get min then it should return us the value s_2 because this is the current present minimum element
14:39:31
inside the given stack. So these are all the operations that we need to do. We need to solve all of these in big of one
14:39:38
time which means we will have to do something different when we are designing our stack. So what are some of
14:39:45
the considerations that we can do? The thing is this push method, pop method
14:39:50
and top method. All of these three methods can operate in big go of one time. No issues with that. In either
14:39:57
case, this get min is little bit tricky because we will we will need to know that what is the minimum element at any
14:40:05
given moment. Now the very first thing that comes to our mind is that when we are designing the stack uh why don't we
14:40:11
just have an extra variable called min to keep track of the minimum value we have encountered so far. So currently
14:40:17
this is an empty stack. Let's assume that we enter value number five. So this has been the minimum value so far five.
14:40:22
Next we add value number six. So five is still the minimum value. Next we add value number two. So and once again we
14:40:29
update this and add two over here. Once again we add value number seven. So now currently the minimum value is two. But
14:40:36
now there is one problem that you did not see and that problem is that let's assume that we decide to pop one element
14:40:42
out. So now currently seven is no longer here. But once again the minimum v variable is still two because that is
14:40:48
the minimum variable. Let's see let's say that if we do pop once again. So once again two is now no longer inside
14:40:54
the given stack as well. So now if we do min operation we don't know that what is the minimum value inside the array
14:41:00
because we just overrode the value. So if we have to check for the minimum value we will have to pop all the
14:41:06
elements out of the stack and then find the minimum value. That is option number one which takes big of end time. And if
14:41:12
we don't do that, we we basically don't have any other way. So now to overcome this issue and to keep track of the
14:41:19
minimum value at every single variable, we can actually do things slightly differently. So the moment we are
14:41:26
storing the values inside the given array, we are actually storing different nodes, right? For every single location.
14:41:32
Now in this design of node, we can actually have node have multiple items,
14:41:37
not only just its value. So let's assume that this is our given node and so in the node I'm suggesting to add three
14:41:43
values. First value is the value of the node itself that whatever the value we wants to enter that is your integer
14:41:49
value like 1 2 3 4 whatever he wants to put. Next is that what has been the minimum value up to this point inside
14:41:57
the existing stack. And if we keep on updating this value with every single entry inside the stack this would be
14:42:03
pretty easy to maintain. And last thing is the reference to the next node because uh in case we will have to
14:42:10
remove or get rid of the element, we might need to update the minimum value we have entered so far. So let's see
14:42:17
that how would this approach is going to look like. Let's say that we wants to add these values inside the stack. Okay.
14:42:23
So first we wants to add value number three. Currently the node is empty. So because node is empty, we are adding
14:42:29
value number three. What has been the minimum value we have added so far? that is also going to be value number three
14:42:35
and the reference to the next node is going to be null. So we are not going to be concerned with that that this is the
14:42:40
very last element inside the stack. Okay. Now we need to add value number
14:42:46
five. So we add value number five but what has been the minimum value so far. So for that we can either check the
14:42:53
minimum value of the next pointer using this next pointer. So we check that what
14:42:59
has been the minimum value of the next pointer at location number five that is value number three and what is the value
14:43:05
of this current value we are trying to enter that is value number five. So whichever is the smaller number which is
14:43:11
three in this case. So we will still mark three as the minimum value we have been able to find and then we simply
14:43:17
have a reference to the next node. So reference to the next node once again I'm just marking as three but that is
14:43:22
simply going to be this node. Okay. Once again we wants to enter value number one. So now at one what has been the
14:43:29
minimum value up until this point that is this value number three. So instead of using three because one is smaller.
14:43:35
So the smallest value so far is going to be one and the reference to the next node is also going to be this one. Same
14:43:41
way now we wants to add value number seven. But what has been the minimum value we have been able to find so far that is value number one. And then just
14:43:47
the reference to the next node and then in the end the value is zero. So now the value is zero. We are trying to see that
14:43:54
what has been the minimum value up until this point that is one. So compared to one zero is smaller. So then this is
14:44:00
also going to be zero. And then we simply have a reference to the next node. Okay. So now this is what our uh
14:44:06
stack looks like. We are simply updating the node that we are storing uh the values in. And now let's see each of the
14:44:13
operation. So I just mentioned that push operation can happen in big off one time because we are just simply pushing one
14:44:18
node inside the stack. Uh let's try to do a pop operation. So pop operation can
14:44:23
also happen in big of one time because we are simply popping one element out. So we will get rid of this element.
14:44:28
Okay. Now once again let's try to do the top operation. So top operation we need we can return seven immediately because
14:44:35
that has been the latest value we we find. And then if we do the get min operation this can also happen in big
14:44:41
off one time because we can simply find the minimum value we have been able to identify so far. So this is the logic on
14:44:47
how we are going to solve this problem. basically by simply redefining the way we are storing the values and then
14:44:54
keeping track of the minimum value at every single position. That is the whole trick. And if we see time complexity in
14:45:00
this case, well time complexity we already know that that is going to be big of one. And in terms of space complexity, well this is debatable but I
14:45:08
think it it has to be big of one because anyways we are being asked to create a stack. So we cannot create extra space
14:45:13
for that. So first let's define the node for our given class where we are going
14:45:18
to store three values. First one is the value of any particular position. Next is the min value and third is the
14:45:24
reference to the next node and this is just a simple constructor to store the values. Okay. Now coming back to our
14:45:30
main class. We are going to have a private node head and we are going to initialize our data structure here. Next
14:45:37
we are going to have a main push method. So whenever we need to push any single
14:45:42
entry, so if the value is very first then we are simply going to provide the value as it is. Then minimum value is
14:45:49
also going to be the same value because there are no other entries inside the stack. And then the next element would
14:45:54
be simply null. If that is not the case, we are going to add a new node where we are going to keep the value as it is.
14:46:01
Then for the minimum value, we are actually going to compare it with the current value and the minimum value we
14:46:07
have been able to find so far. And that we can simply find uh using the next node. And then as a part of the next
14:46:14
node we are simply going to point to the head node. And this is going to be keep on updating with every single entry. Uh
14:46:20
for the pop it's very simple. We simply uh take the very first element that is currently present. For the top we simply
14:46:26
return the very first element and then inside the for the get min method we simply return the minimum value for the
14:46:33
head. And this is the whole solution. Let's try to run the code.
14:46:39
Okay, seems like our solution is working as expected. Let's submit this code
14:46:45
and our code runs extremely fast compared to lot of other solutions in terms of time complexity and very
14:46:51
efficient in terms of space complexity. So once again I will be posting this in our GitHub repository so you can check
14:46:56
it out from there. Thank you.
14:47:05
Hello friends, hope you're having a fantastic day today. So now we are going to do an awesome stack problem that is a
14:47:11
actually a lead code premium problem. So this is going to be really interesting, very popular question and very
14:47:17
interesting subject. So without any delay, let's get started. Okay. So the lead code problem we are going to solve
14:47:22
is called max stack. This is actually a lead code hard problem. And the thing is because this this is a lead code premium
14:47:29
problem. Uh I took this description from another website called leadcode.ca. So
14:47:35
thank you so much to whoever maintaining that that website. Now we need to design a max stack class that supports these
14:47:42
five functionalities. Now if we see the functionality the first three are pretty common where we are pushing an element
14:47:48
down the stack where we are popping an element out of the stack and where we are just checking what is the top value
14:47:55
inside the given stack. These three are the common functionality of any particular stack. Then we need to add
14:48:02
two more methods where first one is a peak max method uh and second one is the pop max method. So if we do the peak max
14:48:09
method we will need to know that what is the maximum element currently and if we do pop max then we will have to pop the
14:48:16
maximum element that is right now inside the stack outside. So let's try to see
14:48:22
the solution for this problem. So logically u let's assume that currently
14:48:27
we have an empty stack. Okay. So we have the option to use five operations and so
14:48:33
let's try to first quickly push some elements inside down the stack. So if we let's push value number three and then
14:48:39
value number five and then value number one. Okay. So now currently we pushed a few elements. Now if we want to pop and
14:48:46
let's just add one more. Now if we want to pop we can pop one element out as well. So if we do the pop operation then
14:48:52
we will we won't have value element number seven. Now we can also do a peak operation. So if we do peak operation
14:48:59
then we can simply check that what is the very first element. So answer of this is going to be one. Then if we do
14:49:05
if you want to do peak max which means we should see that what is the current
14:49:10
maximum element present inside the given array which means the current maximum element present inside the given array
14:49:17
is actually value number five. Even though it is not at the top of the stack this is the current maximum element. So
14:49:24
this needs to be value number five. And if we have to pop max then we need to
14:49:29
pop the value number five out of the stack not value number one. even though one is the very first element. So this
14:49:36
is how we will have to design this algorithm and design data structure in
14:49:41
order to keep these values. Now we know that completing these uh items is very
14:49:48
simple and very similar. No issues with this one. This is a regular stack functionality and every single language
14:49:53
like language like Java, Python, C++ they have they all have their own stack versions that we can simply use. The
14:50:00
problem comes when we need to do this peak max and pop max problem uh
14:50:05
operations because the thing is this is actually slightly complicated because of
14:50:11
variety of reasons. Now the very first thing that comes to our mind is to have a variable called max where we are going
14:50:17
to store the maximum value that we have been able to identify inside the given array and this should make our lives
14:50:24
easier. This is the primitive logic we can think of where let's assume that we add value number one. So we need to
14:50:30
update the value of max to value number one. Then once again we add value number six. So we once again because six is
14:50:37
greater than one. So so far the maximum element we have been able to identified is six. Then we have value number three.
14:50:42
So three is not greater than the current maximum element which means we don't update anything or we don't do anything.
14:50:49
Now after this uh let's say we add ele value number eight. So once again the maximum element needs to be eight. So so
14:50:56
far you must be thinking that hey this seems pretty convenient why don't we just have one value to keep track of the
14:51:01
maximum element and at any given moment I want to see that hey what is the maximum element I can just simply look
14:51:07
at this variable and find the answer the problem is when we do the pop operation
14:51:12
out of this given stack then there would be an issue because now let's say that I decide to pop this eight so if I do if I
14:51:20
pop this element 8 I know that now 8 is no longer the maximum imum element
14:51:25
present inside the stack but I don't know what is the other element that is
14:51:31
the maximum element but instead of just having one simple variable max we
14:51:37
actually need to have a variable another stack called max where for every single
14:51:45
entry inside the original stack for that entry we will have to keep track that
14:51:50
what has been the maximum element that we have been able to identify it so are and keep updating that list depending on
14:51:58
the how we push out or pop out the elements from the given stack. So let's
14:52:04
let me try to explain what I mean. The idea is let's assume that for the max we have to worry about two operations.
14:52:11
First one is the peak max where we are simply watching that what is the max element that is currently present and
14:52:17
second one is the pop max where we are popping the maximum element out at the current position inside the given array.
14:52:24
So we have created our own max stack array uh sorry max stack. So this is our
14:52:30
max stack and this is our regular stack. Okay. Now let's assume that I wanted to enter value number one. So what I'm
14:52:36
going to do is I'm going to add value number one. Currently this max stack is also empty. So so far the maximum
14:52:42
element at this position I have been able to find is also one. So I'm going to store value value number one over
14:52:47
here. Once again I identified value number six. So because value number six
14:52:53
is greater than one. So I'm just going to put six as normal value over here. But over here because value number six
14:52:59
is greater than value number one. So I'm going to say that up until this point of
14:53:05
the stack the maximum value I have I have been able to identify it is six that I have presented over here and some
14:53:12
reason if I decide to pop this element out of the stack then I know for sure that this element also needs to be
14:53:18
popped out and then the maximum element at this position will be corresponding to the maximum element at this position
14:53:24
that is value number one. So which is pretty convenient for us. Now let's try
14:53:29
to add one more element. Let's say three. Now once again even though we added value number three over here so
14:53:36
far the maximum value we have been able to identify up until this point is once again six. So we are once again going to
14:53:42
mark value number six over here. And then once again let's say we add value number eight. So once again we are going
14:53:49
to add value number eight over here because that is the maximum value we have been able to identify. So so far
14:53:55
let's repeat what we have done. We did the push operation in big go of one time. No issues with that. Now at this
14:54:02
at any given moment we can also do the peak operation. Uh and the moment we do
14:54:07
peak operation whatever element is located at the top of the stack we should be able to see that. So this is
14:54:12
also going to happen in big off one time. So once again no issues with this one. So we already took care of two
14:54:18
variables. We can also do the pop operation easily from the stack. So pop
14:54:23
operation can also be done in big of one time and we can do peak max as well in big of one time because this is also
14:54:31
being h happening or maintaining it in constant time. So this also happens in constant time. So we took care of four
14:54:38
operations in big of one time just by simply using these two different stacks. But now the important thing is that how
14:54:45
we are going to manage the pop max operation. For that we will also have to do the pop. So let's try to first do
14:54:52
couple of pop operations. If I pop element number eight out of the given stack, which means now stack does not
14:54:58
contain eight value anymore. And I will also have to update the maximum element up until this point as well. Okay. Now
14:55:05
at this position, let's say I decide to do pop max. So if I do pop max at at
14:55:11
this moment, I should not be kicking out value number three from the stack
14:55:16
because this is not the maximum element so far. the value I should be kicking out is actually going to be the value
14:55:23
number six. So what I'm going to do is that I'm going to kick value number six
14:55:29
out of this given list up until every single point that I have been able to
14:55:34
iterate so far. And the moment I kick value number six out, I'm going to do a
14:55:40
peak operation to see that if this given current maximum value, if that is
14:55:46
greater than the current maximum value I'm left with. And if that is the case, then I will need to update the given max
14:55:54
element to in incorporate value number three as well. Because remember that in
14:55:59
the previous state in this state we did not had value number uh six as part of
14:56:06
the given uh sorry value number three as part of the maximum value so far. But because we did the pop max we kicked a
14:56:14
value number six out and at the same time we will also have to pop these two elements out as well and we would be
14:56:20
left with value number three. Okay. So this is the whole thing that we need to do and this is how we can solve this
14:56:26
problem using two stacks in order to con convey this message. So this is the
14:56:32
whole solution and using this we can complete everything in big go of one time all five operations. So now let's
14:56:38
quickly see the coding solution and then things will make much more sense. Okay.
14:56:44
So now since this is a lead code premium problem and we don't have that subscription at the moment. I'm just going to explain you the solution in the
14:56:50
notepad but this code would work fine and the code is also present in in our GitHub repository. So let's understand
14:56:56
the code. So first we are going to create couple of inte couple of stacks for stack and max stack. Now for the
14:57:04
push and for the pop and for the top we need to the all of these three are standard operation. The thing is pop and
14:57:11
top are going to remain the same. The only problem is that for the push operation we actually have to push the
14:57:18
element in both the places. Which means in the stack we are just going to push it as a regular push push entry. But for
14:57:25
the max stack we will first have to check that what has been the maximum element inside the given stack by based
14:57:32
on the definition of this x value so far using math domax function and checking
14:57:38
that what has been the current maximum in the max stack versus the current value we are trying to enter. So we are
14:57:43
always maintaining the maximum element for any given x element inside our max
14:57:49
stack stack. Okay. Then for the pop operation we will have to pop the element from both the places max stack
14:57:56
and also from the given regular stack. For the top operation we simp simply have to check that what is the maximum
14:58:03
element on our regular uh stack. Uh and we can just do a peak operation. Now for
14:58:09
the peak max operation we will need to do the same operation but now this time in our max stack stack rather than our
14:58:16
regular stack. And the last one is the slightly more complicated method that is the pop max method where first of all we
14:58:24
are going to initialize a new stack called buffer because remember uh the ar
14:58:29
the value we are trying to kick out is presented somewhere in the middle in the
14:58:34
regular stack. So meanwhile we don't find that value we will have to buffer that from our regular stack. So that's
14:58:42
why we are going to push every single element uh from our normal stack to the buffer stack until we until we find the
14:58:49
top element to reach to the max and then we will simply pop that element out from
14:58:55
the regular stack. At the same time we are also going to pop that element out
14:59:00
from our uh Mac stack as well. And then in the end in the inside the buffer we
14:59:06
are also going to push all of those elements into our regular stack using
14:59:12
the elements that we just stored inside our buffer stack temporarily. So that's why this pop max method is slightly
14:59:19
complicated method and uh you can see the coding solution present inside our on our GitHub repository. So hopefully
14:59:27
this explanation made sense to you and uh yeah, thank you so much.
14:59:39
Hello friends, hope you are having a fantastic day today. So once again we are going to solve an awesome lead code problem. So without any delay, let's get
14:59:46
started. So today we are going to solve daily temperatures lead code problem that is a medium problem and also an
14:59:51
extremely well-like lead code problem. So the problem statement is quite simple. We are given an integer array
14:59:57
called temperature that represents the daily temperature over a certain span period. Now we need to return a new
15:00:04
answer from this given temperature array such that any particular item in that
15:00:10
particular answers array should define that how many number of days you have to wait in order to generate a warmer
15:00:18
temperature compared to that particular day temperature. So let's try to understand this with an example. Suppose
15:00:24
this is the temperatures array we are given. Now in the input you can see that bunch of different values for every
15:00:30
single day's temperature. Now if we see on this very first day the temperature is 73. Which means how many number of
15:00:37
days we have to wait in order to get a warmer day. Well a warmer day is right
15:00:42
next which means if we just wait one more day we can actually get a warmer day. Same way for 74. If we just wait
15:00:49
one more day, we also get a warmer day because next day's temperature is 75. Now at this 75, if we have to find a
15:00:56
warmer day, then we have to find a day that contains higher temperature than 75. Which means this temperature 76 is
15:01:04
higher, which we can see that that is actually 4 days away. So over here we will have to actually wait 4 days in
15:01:11
order to get a warmer day. Same way for the 71 we have to wait two days in order
15:01:16
to get a warmer day. At position 69 we only have to wait one day to get a warmer day. At 72 once again we will
15:01:23
have to wait just one day because next day 76 which is warmer. At the 76 we do
15:01:29
not find any particular warmer day subsequently which means we cannot find
15:01:34
a warmer day. So we are just going to mark this as zero that no warmer day exist in front of the value 76. and last
15:01:42
one is 73. So since this is the very last entry, we don't know what the upcoming temperatures looks like. So we
15:01:48
are also going to return zero. And this is the answer array that we need to return. Uh that defines the temp days
15:01:55
you have to wait in order to get a warmer day from any particular day.
15:02:02
Okay. So first let's try to understand a brute force approach to solve this problem. The idea is very simple. We
15:02:08
simply go to a day and then we keep on iterating the array until we find the
15:02:13
next day that has higher temperature. The moment we find this one, we actually find the difference between the index
15:02:19
positions and whatever the difference is, we mark that in the answer. So for this first one, we can mark first as the
15:02:25
answer. For the second one, once again we are going to repeat the same process. We are going to iterate over every
15:02:30
single value inside the array till we find a higher value and which we find 2 days later. Same way we are going to
15:02:37
keep on repeating the same operation and eventually we would have our entire answer array to be populated. Now this
15:02:44
is the most simplest method but we can inherently see some issues with this
15:02:49
approach. The number one issue is that at any given position we will actually have to traverse over maybe the entire
15:02:56
rest of the array in order to find the optimal solution. What if let's assume that this instead of being 50 maybe this
15:03:03
was 80 and we don't have any particular solution in mind we would have still iterated over the entire array and then
15:03:10
once again in order to find the lower temperature for this next element we would still have to iterate over the
15:03:17
entire given array maybe this was 82 so in this this case this is an inefficient
15:03:22
approach and if we see time complexity for brute force approach is going to be big of n² in the worst case scenarios So
15:03:29
let's try to see if we can improve upon this time and space complexity or not.
15:03:36
The thing is at this given location at the very first moment we don't know that
15:03:41
what is the temperature that is higher than this one because we have only iterated this one element right but what
15:03:48
if we are at this element we can at least predict that how many elements
15:03:53
actually has lesser temperature than this and based on that we can immediately update that temperature and
15:03:59
we can immediately say that for if we are at let's say value number 75 Then at 75 we should be able to tell
15:04:06
that 74 is only one day away from having its warmer day. And same way at 74 we
15:04:14
should be able to tell that 73 is actually just one more one day away from having a warmer day. Same way at 72 we
15:04:21
should be able to tell that 69 is only one day away. So how can we actually do
15:04:26
that? For that we will have to find some way to actually iterate the array in one
15:04:32
direction. Note that what the current temperatures are and based on that we
15:04:37
will also have to check that what are the immediate temperatures that are actually smaller than this current
15:04:44
temperature or greater than this current temperature so that we can mark their answers. In order to do that we will
15:04:50
have to use an extra data structure to store the values of all the temperatures for which we have not been able to find
15:04:57
the warmer days. Second thing is for any particular temperature not only we will
15:05:02
have to find the warmer day we will also have to find like the immediate warmer day. So for this 745 is actually greater
15:05:10
than both 74 and 73. But we should not waste our time marking this 73 as having
15:05:16
a warmer day as 75 because there is 74 that is more closely associated with 73
15:05:22
which means we have to worry about the immediate before elements. So we are traversing in one direction but the at
15:05:30
the very quickly we will have to understand that what was the last item we were at before moving to any
15:05:36
particular previous elements. So the best data structure in this case is going to be a data structure that
15:05:41
contains the property of last and first out and the answer becomes very simple that we are actually going to use a
15:05:48
stack to solve this problem. Now how we are going to use the stack is actually
15:05:53
quite interesting. Let's first understand couple of properties. Number one thing is we are using the
15:05:58
temperature to compare the difference between any two given values which means
15:06:03
we are dealing with the value of this given array. But in the answer we need
15:06:08
to store that how many number of days are apart between any two entities and
15:06:13
that we can find using the index values. Why? Because at index value 0, we have
15:06:19
this value 73. And at index value 1, we have this value 74. Which means 70 uh
15:06:25
index value 0 is only one day away from finding a warmer day because index value
15:06:31
1 minus index value 0 becomes actually value number one. So this is how we are
15:06:36
going to find the answer. Which means in the stack it would make more sense to store the index positions rather than
15:06:43
storing the actual values. But using the index positions, we can very quickly
15:06:48
look up inside the array, find the answer and then subsequently traverse the answer. So after this long
15:06:54
explanation, let me walk through the solution that I'm proposing. So currently we are at zero index. The
15:07:00
value is 73. Currently we don't have any value inside the stack. So we are going to add index zero inside the stack.
15:07:07
Okay. And now we are at index position number one. The value is 74. The very
15:07:13
first thing we are going to do is we are going to check that whether the value located at zero position which means the
15:07:20
value located at temp of zero if that is actually less than the current index
15:07:26
positions we are at. So if that is less than the temp of one which is correct condition because this one was 73 and
15:07:33
this is 74 which means 70 this value can be popped out of the given stack and we
15:07:40
can actually mark the answer for this one by doing the subtraction between the current element minus the index position
15:07:48
that we just kicked out from the stack. So this is going to be just one where we
15:07:54
did a simple equation 1 minus 0. Okay, now we are going to put 74 in the stack
15:08:00
but we are going to put the index value. So now in the stack we have index position number one. Now once again we
15:08:05
are at index position number two. So this value is 75. 75 is a greater than
15:08:10
74 which means we can do 2 minus one and the answer is 1. So we can store that that 74 is 1 day away from finding a
15:08:19
warmer day. Now we popped out one from the stack. Now let's add entry number
15:08:24
two inside the stack. Okay, now we are at this position 71. So currently 71 is
15:08:31
actually smaller than 75 which means we don't for 75 we have not yet found a
15:08:38
small a warmer day. So we are going to add entry number three inside our stack as well. Next we are going to be at
15:08:45
position number four which is 69. Once again 69 is actually uh less than the
15:08:51
current top value we have inside the index which means we haven't found a warmer day for this top element and we
15:08:58
are going to add one more element uh that we haven't found a warmer day for. Okay. Now we are at position number 72.
15:09:05
So 72 is actually greater than this value the value at index number four. So
15:09:12
we can actually uh find the answer for index number four. So let me just go.
15:09:18
Okay. So this is for index number one. 0 we have one we have. For two we don't have for three we don't have. But for
15:09:25
four we found the value that is 5 - 4. So we can add 1 as the answer for index
15:09:31
number four. Once again the moment we pop out index number four we should not
15:09:36
be pushing index number five yet because we still have to check that whether five is greater than index number three. And
15:09:43
yes it is once again greater. So for index number three we are going to mark the answer as two and same way for index
15:09:50
number two we are also going to mark the answer as uh so sorry for index number
15:09:57
two we are still not able to be able to find the answer because this is 75 and this is 72. So we are going to have
15:10:03
index number two still living inside the stack and then we will have index number five now residing in the stack. Now we
15:10:10
are at index number six. So this value is 76. 76 is actually greater than 72
15:10:16
and so in this case we can actually mark down the answer over here as one for
15:10:22
this index number five and we can get rid of this index number five. Now once again this index number two is also
15:10:29
smaller than index number six. So we need to do the difference 6 minus 2. So we find answer four and we are going to
15:10:35
populate answer four over here. And then we have an empty stack which means there are no more values we need to check. So
15:10:41
we are going to add value number six inside the stack and then in the end next value is value number seven. So 7
15:10:49
is 73. 73 is actually smaller than the current stack value we have. So we are also going to add value number seven
15:10:55
inside the stack. And the moment we reach to the end we are going to fill out all the rest of the elements by zero
15:11:02
that there are zero days that we have been able to find the answers for. And this is what we can return in the
15:11:08
answer. So you see how using a stack we actually need to traverse over just once
15:11:15
on the given temperature array and then we have been able to find the answer which means this is a much better
15:11:20
approach and this is the optimal solution compared to our brute force solution. So let's try to see the time
15:11:26
and space complexity in this case. The time complexity is actually going to be big of n because we are simply iterating
15:11:31
over the temperature array once. Now it could be possible that for some values we might have to go back and find the
15:11:38
values that are smaller than that that where we are doing multiple operations inside the stack but that that number is
15:11:45
going to be limited because we are being told that we can find out that how many
15:11:50
values are there and uh we are only iterating over the values for which we haven't find the answer. And uh in terms
15:11:57
of space complexity once again in the worst case scenario this is going to be big of n because we are using an
15:12:02
additional space additional stack to find the answer.
15:12:09
So the coding solution is actually quite straightforward. First we initialize a number n in order to mark down the
15:12:15
length of the given array. Then we initialize a new answer array of the size n. We also initialize our stack
15:12:21
that we are going to use. Now we simply iterate over the given temperatures array using the for loop. We first have
15:12:28
a while loop condition that while the given stack is not empty and the
15:12:33
temperature that we are iterating over currently if that is greater than the temperature that is currently present
15:12:39
inside the stack. Then we simply mark the index value that is currently
15:12:44
present at the very first element of the stack that we popped out. And then we mark the answer index by doing the
15:12:51
subtraction of i minus the current index position that we have just been able to find by popping the element out of the
15:12:57
stack. And then uh we simply push down the element inside the stack. And in the
15:13:02
end our answer array should have all the answers. So we can simply return that. Now let's try to run this code.
15:13:10
Okay, seems like our solution is working as expected. Let's submit this code.
15:13:18
And our code runs pretty fast compared to most of the other solutions. It is also decent in terms of space
15:13:23
complexity. And once again, the solution is available on our GitHub repository. The link is in the description. So you
15:13:29
can check it out from there. Thank you.
15:13:37
Hello friends. Hope you are having a fantastic day today. So once again we are going to do an awesome lead code
15:13:43
problem and trust me this is an awesome lead code problem. So without any delay let's get started. So now we are going
15:13:50
to solve the lead code problem called car fleet. Now personally this is one of my favorite problems and we can see that
15:13:56
this one is a lead code medium problem and also decently well-like problem. The thing is this is a very long description
15:14:04
for this problem because it covers lot of edge cases and lot of conditions that you have to understand. If you want be
15:14:10
my guest and read the whole description if not let me just point out few important topics and then we will try to
15:14:17
understand what the problem is asking us to do through an example that would make things much more simpler. So first thing
15:14:23
is we are being told that there are n cars going in the same destination along
15:14:28
one lane road. So it's a single lane road and we are told that the cars are not going to be overtaking each other.
15:14:34
This is not fast and furious. This is lead code. Okay. Then we are also given a target miles that we need to reach.
15:14:41
That is the final destination for our cars. Now we are given two integer
15:14:46
arrays. First one is position and second one is called speed. So position defines
15:14:52
that what is the starting position for any particular given car compared to
15:14:58
that target distance. Okay. And the speed is at what speed that particular
15:15:03
car is running on. So we are given both the values inside the car. Now we are being told that cars are not going to
15:15:10
overtake each other but if they are close enough we can consider them arriving at the destination at the same
15:15:16
time. And any car arriving at the destination or set of cars arriving at
15:15:22
the destination would be considered as car fleet. And now we need to consider
15:15:27
that how many number of different car fleets actually arrive to the destination. So I know that this was
15:15:34
quite complicated and very extensive description. Let's try to make it simpler using some example. So over here
15:15:41
we are given a target value of 12 that we need to reach and we are given the
15:15:46
positions and we are also given the speeds of subsequent cars. So here I
15:15:51
have actually plotted a graph or a number sequence where this 12 is the
15:15:57
target that every single car is trying to reach. Now this C1 C2 these
15:16:02
represents different cars and we can see that based on their positions inside the subsequent array I have already plotted
15:16:09
them on this given line. So this defines their starting position and subsequently
15:16:16
this portion defines that what is the speed that is given to every single car.
15:16:21
Okay. And we are being told that the distance we are trying to cover is 12 miles and the speeds are given in per
15:16:28
hour basis. So which means this car C2 actually travels 4 miles in 1 hour.
15:16:34
Okay. So now we need to understand that how we define car fleets. So let's try
15:16:41
to understand it one by one. So we will try to go over that how every single car
15:16:47
is actually going to reach to the final destination. And we know for sure that no car is going to overtake one other.
15:16:54
So if one car comes closer to the other car, we would consider both of them
15:16:59
reaching to the destination at the same time and they would be part of one single fleet. So first let's see. So
15:17:06
currently this car C1 is located at position number 10 and its given speed
15:17:11
is 2 mph. We know that this C1 has to be the first car to reach to the
15:17:16
destination because it is the closest car to the destination. So the in the
15:17:22
first hour this car is actually going to reach to the destination and it's going to take 1 hour. But during this 1 hour
15:17:29
period because how do we come up with this 1 hour? Because we calculated the distance from the current position to
15:17:34
the final destination we are trying to reach which is 2 mi and its speed is also 2 mi. So we can easil easily
15:17:40
calculate the time uh that it takes to reach to the destination. Now for this C2 also subsequently the C2 would also
15:17:50
reach to the destination in just 1 hour. So based on this we can conclude that
15:17:57
both of the C1 and C2 are actually going to reach to the destination around the
15:18:02
same time around at 1 hour mark which means C1 would be here and C2 would be right very close to it. So these two
15:18:09
cars are going to reach to the destination in around the same time which means this is going to be one of
15:18:16
the fleet that is going to arrive into the destination. So now we already took care of one fleet. So let's just get rid
15:18:23
of these. Okay. And also let's try to understand that we have already spent 1 hour. So during this 1 hour what would
15:18:30
be the position of all of these cars. So during 1 hour the C4 would have traveled
15:18:35
1 kilometer. So C4 would be here. Same way this C5 would have also k
15:18:42
completed 3 km because its speed is three. So after this 1 hour this C5's
15:18:48
position should have been at position number six. But at position number six, we can clearly see that C4 is already
15:18:55
present. Which means after 1 hour, the position is going to look something like this where C4 and C5 are going to be
15:19:02
right close to each other. Now remember that the speed of the C4 is one and speed of the C5 is three. But because C4
15:19:10
is ahead compared to C5, even though it has higher speed, it is not going to overtake it. And it is only going to
15:19:17
reach to the destination when the C4 arrives. But essentially both of these
15:19:23
cars are also going to reach to the destination in around the same time. And how much time will it take? Well,
15:19:29
currently this one is at position number six. So it is going to take six more hours and we already spent 1 hours.
15:19:34
Which means this C4 is going to take 7 hours to reach to the destination. And
15:19:40
because C5 is behind that and it is able to catch up to the C4, it is also going
15:19:45
to complete and reach to the destination in 7 hours. So after 7 hours the second
15:19:51
fleet that would have reached to the destination would be the cars uh that we just saw that is the car C4 and also C5.
15:19:59
So they both will also reach to the destination in around the same time. So this would be our second fleet that is
15:20:05
going to reach to the destination. And now we already spend 7 hours which means
15:20:11
after 7 hour this C3 would have been uh around here because its speed is just 1
15:20:17
m per hour. So it would have covered the distance of 7 miles and then still it
15:20:22
would have five more miles to go which means it would still take uh like around 12 hours to reach to the destination and
15:20:29
in the end the C3 car would be the very final car that would reach to the
15:20:35
destination and still this would also be considered a fleet in its own. So over
15:20:40
here we can see that actually we are getting 1 2 and three fleets reaching to
15:20:45
the destination. So for this given input we need to return three as the answer
15:20:51
and this is the whole problem statement. Now I know understanding this problem statement take took us lot of time
15:20:57
because there were a lot of moving parts and moving cars that we had to understand but honestly this is an
15:21:03
awesome lead code problem because if any interviewer dares to give you this problem this is not very difficult to
15:21:08
solve but it's very uh pecular for interviewer to explain also you will
15:21:13
have to navigate through lot of different edge cases and then think about coming up with the optimal
15:21:18
solution. So now I'm not even going to be bothered
15:21:25
to show you the brute force approach because that would be an inst.
15:21:30
So let's talk about the actual complete optimal solution that we can use in
15:21:36
order to solve this problem. And in order to generate the optimal solution, we need to make some assumptions and we
15:21:44
we need to do some calculations. So what are some of the calculations we need to do? Number one thing that is most
15:21:51
important is that for any particular car we will have to understand that how much
15:21:57
time it takes to reach to the end. That is number one thing and second thing is
15:22:02
cars can only reach to the target based on the current sequence locations they
15:22:07
are present in. So even though if we see the car numbers over here this C1 and C2
15:22:13
are based are located at the correct space but this C3 is actually going to even though this is the third car this
15:22:20
would this has to be the last car to reach to the end. So number one thing we are going to do is we will try to find
15:22:27
that how much time does it take for any single car to reach to the end. We will try to store this information with the
15:22:33
cars. So we actually have couple of ways to store this. We can either store it using a hashmap uh that would only make
15:22:40
things more complicated because we don't need like a constant time access to that
15:22:45
data and same thing can be achieved using a two-dimensional array as well. So we will try to use it uh store it
15:22:52
using two-dimensional array. Okay. So in the two-dimensional array we are going to store the information for a
15:22:58
subsequent car and how much time does it take to reach to the end. That is number one thing. Number two thing we are going
15:23:04
to do is that we will actually sort these cars based on their positions. So
15:23:10
number one car in that is going to reach to the destination is going to be the car that is closest to the destination
15:23:17
position. So based on the position size we are also going to sort them and once we have that we would be able to
15:23:24
identify the answer quite easily. So now first let's try to understand that how do we actually calculate how much time
15:23:30
does it take for any single car to reach to the destination and that is a very simple calculation. All we need to do is
15:23:37
we need to calculate the distance between the current position and the destination position and whatever this
15:23:44
distance is we need to divide the speed by that distance and that would give us
15:23:49
the time on that it that that particular car would take to reach to the final
15:23:54
destination. Okay. So now the idea is quite simple. So let's just do that. So for C1 currently we can see that this is
15:24:02
located at position number 10 and it needs to reach to the position number 12 which means the distance is 2 and the
15:24:09
speed for C1 is also 2 m per hour which means it is going to take 1 hour for C
15:24:14
to reach to the destination. Same way for C2 it is also going to take 1 hour to reach to the destination. Same way
15:24:21
for this C4 it is actually going to take 7 hours to reach to the destination
15:24:26
because the difference between 5 and 12 is 7 and the speed of C4 is 1 mph. Same
15:24:32
way for the C5 the distance the distance is also going to be 3 9 km uh sorry 9 mi
15:24:40
and then the speed is three. So it is only going to take 3 hours to reach to the destination and last one is the C3
15:24:48
car. So for C3 it's actually going to take 12 hours to reach to the destination. Now we have our this list
15:24:54
ready. Now let's try to sort this given list based on the position of the cars.
15:25:00
Which means once again C1 is at the correct position and C2 is also at the correct position. Both times are 1 hour
15:25:07
and 1 hour. Then we have the car C4 and C5. So for the car C4 it is uh it is
15:25:15
going to reach into the 7h hour mark and car C5 should reach in 3 hour marks if
15:25:21
there were no cars ahead of it. And the last one is the C0 car or uh I think C3
15:25:28
car. So C3 car is going to take 12 hours to reach to the destination. Okay. So
15:25:34
let's quickly do a reagap what we did. We found out how much time does it take
15:25:39
to reach to the destination. Then we sorted all of these cars based on the
15:25:45
position where they are compared to the start to the target location. So the
15:25:51
higher the position the first it is going to be inside our l. And in order
15:25:56
to store this information we are going to be using a 2D array. Now after having
15:26:01
this information it becomes very easy for us to solve this problem because all we need to do is we simply have to check
15:26:09
because we know for sure that this has to be the first car to reach to the destination at any given moment. We
15:26:16
realize that the speed of this is actually lesser or equal to the speed of
15:26:24
its subsequent car. then we can conclude that both of these cars would reach to
15:26:29
uh at the same time. Let me rephrase. I used the word speed but the the correct
15:26:35
word should have been time. So if the time it takes for the C1 car to reach to
15:26:40
the destination is 1 hour and we see that for C2 the time it takes is also 1
15:26:47
hour which means C1 and C2 both are going to reach to the destination around the same time just in a scenario where
15:26:54
C2 is just behind C1. So we can conclude that these two has to be one single
15:27:00
fleet. So this becomes our one of the fleets. Now in the second scenario, we
15:27:06
have the time it takes for C4 to reach to the to the destination as 7 hours and
15:27:12
the time it takes for C5 to reach at the destination at 3 hours. Which means C5
15:27:18
actually is much faster than C4. So eventually C5 would be close enough or
15:27:25
just behind C4 before C4 actually reach to the destination. Let's try to once
15:27:30
again understand using this plot because after the very first hour actually C5 and C4 would both be at the same place
15:27:38
and how do we find out because we can see that the time it takes for both of them to reach to the destination. So
15:27:45
these two also has to be part of a simple fleet. Now say this last for the
15:27:52
C3. Instead of this being 12, maybe this also took 3 hours to reach to the
15:27:58
destination. Then C3 would have also been part of this fleet because C3 would
15:28:03
reach to the destination three in 3 hours. C5 would reach in 3 hours and C
15:28:09
C4 is going to block both of them and cause both of these cars to reach at 7
15:28:14
hour mark because C4 is ahead compared to C5 and C3. So this would have been part of this fleet as well. But in this
15:28:21
scenario because the time C3 takes to reach to the destination is actually greater than the previous fleet the
15:28:28
largest value in the previous fleet. Then we can conclude that this C3 is not
15:28:34
going to be able to catch up to the C4 and C5 fleet. So this is going to be our
15:28:39
second fleet and in the end the C3 is going to be our third fleet. So that's
15:28:46
all you need to do to solve this problem. Once we do have the comp the sorted version of subsequent cars with
15:28:54
the time it takes to reach to the destination, we can actually very easily compute because for every single fleet
15:29:01
all we need to check is that what is the longest time it takes uh for those fleet
15:29:07
to reach to the destination. So in this case for the C4 and C5 it's going to take 7 hours to reach to the
15:29:13
destination. So if this number would have been anything less than seven then
15:29:18
it would have been part of this uh C4 fleet but because it's not less than seven so this has to be a fleet on its
15:29:26
own and uh that's it that's what we need to do and this is the whole solution. So
15:29:32
now you see how beautiful this problem is and how awesome the solution is. Like that's why this is really one of my
15:29:38
favorite questions because it's a combination of math and data structures and then how do you make things more
15:29:44
efficiently and how can you think about uh different scenarios and different mathematical equations and stuff like
15:29:50
that. Okay. So now let's try to understand the time complexity. It is going to be big of n because we are
15:29:56
going to be simply iterating over the given input array bunch of times. But still it is going to be big of n. But
15:30:03
you forgot one critical thing that is we will also have to do the sorting operation. And that is actually going to
15:30:09
cause our time complexity to be big of n login. And if we see space complexity,
15:30:15
well for the space complexity is actually going to be big of n square because we are using a 2D array to store
15:30:20
the information of the cars uh to its subsequent time it takes to reach to the destination. Overall this is also a very
15:30:27
good time and space complexity. Now let me know in the comments if you want also want to see a solution using a monotonic
15:30:34
stack because this is pretty popular problem for that. So if you want I can also show a solution with that. But I
15:30:41
think this is a good enough solution for your interview. Your interviewer is going to be more than happy. And now
15:30:47
let's just quickly see the coding for this one.
15:30:53
So the coding solution is quite simple. First of all, we create an integer n uh
15:30:58
to store the length of the given input array. And then we initialize our 2D array that we talked about where we are
15:31:05
going to store the information about cars and it subsequent time it takes to reach to the end. Then we are simply
15:31:11
going to iterate over the given input array and we are going to populate our cars d 2D array that we just created
15:31:19
where we are going to mark the positions of the car and also we are going to calculate that how much time does any
15:31:24
single car takes to reach to the destination. Then we are going to do the most important operation where we are
15:31:30
going to sort the given cars based on the current positions of the given cars.
15:31:37
Once we have that now it is very convenient to solve this problem. We are going to initialize a counter zero that
15:31:43
this is going to calculate the fleet on what time it is going to arrive and then
15:31:48
we are going to have another variable where it is going to keep track that what was the previous time for the car
15:31:53
to reach to the end. Then we are simply going to iterate over the given input uh 2D array cars and we are going to check
15:32:00
that if the value of the any particular given car is actually greater than the
15:32:06
previous time which means that is a new fleet being created. So we are simply going to create a new fleet or add the
15:32:14
value to the counter and also we are also going to mark the previous time of the last car that just came in and
15:32:22
that's it. In the end, we can simply return this counter that we have created that was keeping track of all every
15:32:27
single fleet. And now let's try to run this code.
15:32:45
Okay, seems like our solution is working as expected. Let's submit this code
15:32:52
and our code runs decently efficiently in terms of time complexity, extremely efficiently in terms of space
15:32:57
complexity. And once again the code is present inside our GitHub repository. So you can go and check it out from there.
15:33:03
Thank you.
15:33:12
Hello friends, hope you are having a fantastic day today. So in this video we are actually going to solve a very popular lead code problem. So without
15:33:18
any delays, let's get started. So the lead code problem we are going to solve is called evaluate reverse polish
15:33:23
notation. And we can see that this is a lead code medium problem and also an extremely well-like problem on lead
15:33:29
code. The problem statement is quite straightforward but it actually has bunch of different conditions that we need to understand. So we are given an
15:33:36
array of strings called tokens. Now these strings represents an arithmetic expression in the reverse polish
15:33:43
notation. Now we need to evaluate the expression and we need to return the integer that represents the value of the
15:33:50
expression. Now let's try to see some of the conditions that we are given. Number one, the valid operations are plus,
15:33:56
minus, multiply and division. So these are the four operations that we can we can imagine to expect in our uh string
15:34:02
that is coming in. Now we are being told that each operand may be an integer or
15:34:08
another expression. So we will see this in in another example. Then we are being
15:34:13
told that the division between two integers always truncates towards zero which means we are always considering
15:34:19
the ceiling value ceiling value or sorry the floor value of any equation and then
15:34:25
we are be being told that all the inputs are going to be valid and there are not going to be any issues. So let's try to
15:34:31
see one example one very simple example. So in this case the answer is going to be that the moment we identify an
15:34:37
operator we will have to go back and take the previous two elements and if these two are whatever the numbers are
15:34:43
we are going to be using that with this operator. So we are going to be treating this as a we are going to be treating
15:34:49
this as b and since this is a plus operator we are actually going to be doing a plus b. So we need to return
15:34:55
three as the answer in this case. Let's try to take some more slightly more complex examples. First we are going
15:35:01
okay so this is the number we move a move ahead once again a number we move ahead we identify an operator so now we
15:35:08
are going to be treating these two values as a and b so we are going to be doing a + b so 1 + 2 so the port the
15:35:16
answer of this portion is actually going to be three equation looks like 3 and
15:35:21
then 3 and then plus so once again we are going to be doing 3 + 3 so the answer is six so out of this operation
15:35:28
we need to return six as the answer So this is the whole logic of what the
15:35:33
problem is actually asking us to solve that whenever we are given the values we keep moving forward until we find either
15:35:39
one of these three operators like plus minus multiplication or division. Uh the moment we identify these four operators
15:35:46
we are going to be treating the previous two values as a and b and then apply this operator and then keep on repeating
15:35:52
the same process until we run out of all the every single digits inside the given inputs and we are being told that the
15:35:57
all the inputs are valid. Now after this extensive explanation let's try to
15:36:03
understand the most simplest brute force approach. So brute force approach is actually quite straightforward. Uh
15:36:08
suppose we are given the values four 5 plus and then minus and then seven.
15:36:14
Suppose these are the values we are given. So idea is that we are going to keep on iterating one by one. The moment
15:36:20
we identify an operator then once again we go back to the previous two elements
15:36:25
and we use it with that operator. And then once again uh we identify okay so now this becomes 9 and then minus and
15:36:32
then seven. So once again we keep on repeating the same operation using the operator. But the thing is many times
15:36:38
for let's assume that this if this is a very long string and we identify operator at very late. The moment we
15:36:44
identify operator once again we are going to be repeating the same process in order to keep find the values a and b. So this becomes very tiresome
15:36:51
operation. So the idea is that we need to make it better and uh find some
15:36:56
smarter ways to keep track of all the elements from the point we find the operators in the reverse order and also
15:37:03
have an idea on how we can keep on moving forward with the given input array and start parsing the values. So
15:37:09
these are the two main considerations that we will have to understand. So the idea I'm suggesting is that we can
15:37:15
actually use stack to solve this problem. So suppose this is the long operation that we are given. Now the
15:37:21
idea I'm suggesting in using the stack is that at the very beginning we are
15:37:26
actually going to be iterating the same way we are iterating all the values we find we are going to be pushing these
15:37:32
values inside the stack. The moment we identify the operator, we are going to be popping the previous two elements and
15:37:38
treating them as uh a and b and then applying that operator with that value.
15:37:43
And once again, whatever the answer we find, we are also going to be p pushing those answer inside the stack and then
15:37:49
we are going to keep on repeating the same process until we identify the operator and then when we reach to the
15:37:55
end, we should have our answer ready because we are being told that the given input is actually valid. So let's see
15:38:00
the solution in action. So currently our stack is empty. Now we are at very first element number two. So we are going to
15:38:07
be pushing element number two inside the stack. Now we are element number three and once again element number seven.
15:38:13
Okay. Now we identified an operator plus. So the moment we identified the plus operator we are actually going to
15:38:18
be popping these two values out. So if we do that we will have value 7 and three that we need to do the sum of. So
15:38:25
7 + 3 is going to give us the answer 10. So currently the answer of this portion
15:38:30
is going to be 10. So we are going to be pushing this 10 inside the stack. And now look at the stack. It actually
15:38:36
contains the equation for this portion because sum of these three values is 10
15:38:41
that is present over here. And then two was already here. Now we have 10 and two. Once again we identify
15:38:47
multiplication sign. So we need to do 2 * 10. So we get the value as 20. So now
15:38:52
once again we are going to be pushing the value 20 because we already popped out 2 and 10. Okay. So now we have value
15:38:59
20 inside our array and now we once again identified value number eight and then once again value number 19. So
15:39:06
let's push that. Okay after doing that now we identified car symbol plus. So
15:39:11
once again for plus we are going to be doing 8 + 19. So the answer is going to be 27. Okay. So now we are because we
15:39:19
popped out 19 and 8 we push 27 down and then we have this minus operator. So
15:39:25
last operation we are going to be doing is 27 minus 20. So the answer is going to be 7. So 7 is what we need to return
15:39:32
in this case to solve the problem. And this is the whole solution that I'm proposing using the stack. Look how
15:39:38
beautiful it is. Look how at any given moment but but the moment we identified the operator we can actually find the
15:39:45
previous two elements back and we can actually do the sum that needs to be done or sum division uh subtraction
15:39:52
whatever. And this is how we can solve the reverse polish operation very beautifully using stack. This is one of
15:39:58
the most awesome way to use stack in the real life problem. And that's why this is such a popular problem that we have
15:40:05
seen in tons of interviews being asked. So if you see time complexity in this case the time complexity is actually
15:40:10
going to be big of n because we are going to be iterating over every single character just once nothing more than that. In terms of space complexity we
15:40:18
are using an additional uh stack. So depending on how apart the characters
15:40:24
are from any operation the size of stack can increase or decrease but overall it
15:40:29
is going to be big of n. So which is good uh and acceptable time and space
15:40:34
complexity in this regard. So now let's see the coding solution for this one.
15:40:40
So the idea is quite straightforward. First of all we are going to be initializing our stack. And then for
15:40:45
every single token we are first of all going to check that if the given token is operator or not. The moment we
15:40:52
identify that if the given token is operator we are going to be popping two values out. So first value we pop out is
15:40:59
going to be our B and second value is going to be our A and then we are going to be applying our operator that we have
15:41:05
found uh using this method. So let's see couple of the helper methods. First helper method is the is operator helper
15:41:12
method where we are simply checking that if the given token is equal to any of these four values and second one we are
15:41:19
applying the operator where we are simply going to go over the given input values that is the string and then a
15:41:26
value and b value and we are simply returning depending on the operator to
15:41:31
whether do the addition subtraction multiplication or division and if none of this case is there we are simply
15:41:37
adding one extra argument but I don't think this is going to uh be called because we are being told that the given
15:41:43
input is valid. If that is not the case and we did not find that these are the
15:41:48
operator by the way uh the moment we identified the operator we also do the calculation and whatever the result we
15:41:54
found we once again push it down the stack. If that is not the case which means the given token is not an
15:42:00
operator. So we simply push it down the stack but we first of all convert the value inside the integer because we know
15:42:07
that this is going to be the integer value and once this loop runs we should have been done with our reverse polish
15:42:13
notation and whatever the value left inside the given stack would be the answer that we need to return. So we can
15:42:19
simply pop the very last element. So let's try to run this code.
15:42:25
Okay, seems like our solution is working as expected. Let's submit this code.
15:42:31
And our code runs pretty fast in terms of time complexity which is pretty awesome. Once again the coding solution
15:42:36
for this problem is present inside our GitHub repository. So you can find it from there. Thank you.
15:42:50
Hello friends. Hope you're having a fantastic day today. So now we are going to solve Facebook's most asked question.
15:42:57
This question has literally been asked 142 times at Facebook. So this is a very
15:43:03
popular lead code interview question and without any delay let's get started. Okay. So the lead code problem we are
15:43:09
solving today is called minimum remove to make valid parenthesis book and we can see that this is a lead code medium
15:43:15
problem and also a very well-like problem. Now the problem statement is quite simple that we are given a string
15:43:22
that contains bunch of different opening and closing parentheses and lowerase
15:43:27
English characters. Now at any given moment if we identify that the
15:43:32
parentheses are in correct sequence like the same number of parentheses that are opened are also closed then we call them
15:43:39
valid. But if we identified some invalid parenthesis then we simply have to remove them. So let's try to understand
15:43:46
this with an example. it would make much more sense and we can see that bunch of the parentheses are actually at the
15:43:51
wrong position. First one we can see over here where we have a closing parenthesis but we don't have any
15:43:58
opening parenthesis somewhere here before which means this is an invalid parenthesis. Same same way uh this is
15:44:04
also an invalid closing parenthesis because though this pair of parentheses
15:44:10
are valid this is not valid and same way we have an additional opening parenthesis. So in this case we have
15:44:16
three parentheses that that are invalid. So if we simply get rid of these three
15:44:21
parentheses that we just identified then we would have our query that will look
15:44:27
like this. And now we can see that uh this entire sequence is actually valid
15:44:33
where we have uh two pairs of opening and closing parentheses. So they are valid and also we have bunch of
15:44:39
different smaller English language characters and they are also valid. So we simply have to identify that which
15:44:46
are the index positions that we need to remove uh in order to make a valid parentheses pair or a valid query. Okay.
15:44:54
So let's simply see the brute force approach very quickly.
15:45:01
Brute force approach is very simple. uh for any query that we are given we can all we need to do is that we simply go
15:45:09
over every single character and the moment we identified either an opening
15:45:14
or closing parenthesis. So in this case we identify a closing parenthesis. So once again we would go back and try to
15:45:20
find an opening parenthesis. If we cannot find it we identified that this one is invalid and then we move forward.
15:45:26
Same way the moment we identify an opening parenthesis once again we would move forward to try to find a closing
15:45:33
parenthesis that is going to match up with that. If we find it that's great. If we don't find it then in that case we
15:45:39
would deem that parenthesis as invalid. And if we keep on moving forward in that direction we would eventually find the
15:45:46
answer. But the thing is there is lot of back and forth we are doing. And essentially for every single character
15:45:51
in the worst case we might have to do like big go of n² work in order to solve this problem which is lot of work needs
15:45:58
to be done just to solve this problem and this is actually a very simple problem to solve. So now let's quickly
15:46:04
see the optimal solution for this one.
15:46:09
So now let's try to see that what would be the optimal solution to solve this problem. And for that we will have to
15:46:15
understand just couple of things that what are the exact checks we are making. Number one thing we are checking is that
15:46:21
at any given moment we identify that any particular opening parenthesis exist.
15:46:26
This can only be valid if further down the road we identify that there exist
15:46:32
some closing parenthesis. Okay. And same way if we identify some closing
15:46:38
parenthesis, this can only be valid if there exist a subsequent opening
15:46:43
parenthesis presented in counterpart towards this one. If there does not exist any which means this is one of the
15:46:50
invalid ones. So using these two conditions what we need to do is for
15:46:55
every single opening parenthesis we need to keep it stored somewhere that there might be a closing parenthesis somewhere
15:47:02
down the line and the moment we identified some closing parenthesis we will have to check that whether there
15:47:08
exist an opening parenthesis immediately before that that is going to match with it. So a very good data structure in
15:47:16
this case would be stack to solve this problem. Why? because stack has the property of last in first out that we
15:47:23
are going to use at at its maximum to solve this problem and let's quickly understand that what I mean now the
15:47:29
thing is through stack we would be I we would be able to tell that which
15:47:35
parentheses is invalid but the thing is we would still need to recreate this
15:47:40
entire string in order to solve this problem so what we can do is the moment through stack we identify that any
15:47:46
particular indices is invalid whether opening or closing parenthesis we can
15:47:51
just simply create maybe like a hash set or some other data structure where we are simply going to keep track of all
15:47:58
the variables or all the index positions that are invalid. This is this will help us to build the rebuild the entire
15:48:05
string after we find out all the invalid parenthesis. Okay. And the logic we are
15:48:10
going to apply is that for a stack uh if the moment we identify that there exist
15:48:16
an opening parenthesis we are going to push the opening parenthesis down the stack. The moment we identify a closing
15:48:23
parenthesis we are going to check inside the stack that whether there exist an opening parenthesis to counter this
15:48:30
closing parenthesis. If it does we are simply going to pop that parenthesis out. So marking that this entire pair is
15:48:38
going to be considered valid. Now for some particular case we identify that there exist a closing parenthesis but
15:48:44
there is no opening parenthesis then this needs to go to the set because this is an invalid entry and using this logic
15:48:51
we would be able to solve this problem quite easily. So let's quickly see the solution that I'm proposing. Okay. and
15:48:57
also let me quickly mark the all the index positions and also initialize a
15:49:03
hash set where we are going to store all the indices. Okay. So very first element is a lowerase English letter element. So
15:49:09
we will just move forward. Now we identified a closing parenthesis. So now
15:49:15
the moment we identify closing parenthesis we will need to check inside our stack that does there exist an
15:49:20
opening parenthesis. Currently the stack is empty because the stack is empty this is an invalid position. So we are going
15:49:27
to mark the index position inside our set as one. Next we will move on towards
15:49:32
the next element. This one is also a lowerase English character. So we move forward. This is an opening parenthesis.
15:49:37
So opening parenthesis has to go into the stack. So we are going to mark its index location inside the stack. So we
15:49:44
identified value number three over here. Okay. Next is also a random character. Now this one is also a closing
15:49:50
parenthesis. So closing parenthesis we check that whether in the stack do we have do we have any entry and yes we do.
15:49:57
So we will actually pop this element out. So we pop this element out. Currently stack is empty. Now because
15:50:02
stack is empty we also identified that there exist an opening parenthesis. So oh sorry a closing parenthesis and we
15:50:09
once again needs to check into the stack but stack is empty which means this is also an invalid character. So we are
15:50:14
going to mark five over here. We get once again we can ignore this one. Now this one is an opening parenthesis. So
15:50:20
we enter over here once again opening parenthesis. So once again we enter into the stack. We can ignore this one. Now
15:50:26
this 10 is also a closing parenthesis. So for the closing parenthesis we can pop one value out. So we pop eight out
15:50:34
from our stack. But the thing is in our stack we still have value number seven left. Which means that this value number
15:50:41
seven is also an invalid stack because we we just run out of all the characters in the inside the string. So we have an
15:50:48
extra opening opening parenthesis as well that we need to remove. So we can mark this value. And now if we remove
15:50:54
this character 1 uh 5 and 7 from our existing string, we would get our string
15:51:01
that uh looks like this where the values are going to be valid and this is what
15:51:06
we need to return in the answer. So basically we can very easily solve this
15:51:12
problem using the stack. If we see time and space complexity, time complexity is going to be big of n where n is the
15:51:17
number of characters that are present inside the stack and space complexity is simply going to be bigo of n as well
15:51:24
because we are using an extra stack and also an extra hash set to store bunch of
15:51:29
different values. Okay, so now let's quickly see the coding solution for this one.
15:51:36
So coding solution for this one is quite straightforward. First we initialize our hash set and our stack. Then we simply
15:51:43
iterate over the given string. Uh and for every single character we first check that if the given character is an
15:51:50
opening parenthesis we push it down the stack. If it is a closing parenthesis
15:51:56
and if the stack is empty which means we identified an unexpected closing parenthesis. So we simply remove add
15:52:03
that character to our remove indices hash set that we have created at its index position. uh and if that is not
15:52:11
the case we simply pop the element out of the stack because stack already has an opening parenthesis. This is what it
15:52:17
means. Now in the end after this particular loop has ended we would have
15:52:22
taken care of all the unexpected closing parenthesis that were present but we still have to take care of the opening
15:52:28
parenthesis and they would still be present as unmatched opening parenthesis inside the stack. So any single element
15:52:35
that is present inside the stack we simply uh take them out and work on uh and add them to our hash set as well. In
15:52:42
the end we simply need to build a string in order to generate the answer. So for that we remove all every single
15:52:47
character that are present inside our hash set uh and then just create and append the string that is that was
15:52:53
already given to us in the input and then we simply return that as the answer. So this is the whole solution.
15:52:58
Let's try to run this code.
15:53:05
And our code works as expected. So no issues with that. Let's submit this code.
15:53:12
And our solution is pretty fast compared to a lot of other solutions. Once again, the coding solution is present inside
15:53:18
the description of the GitHub link that I have provided below this video. So you can go and check it out from there.
15:53:24
Thank you.
15:53:32
Hello friends, I'm a cloud solutions architect at Microsoft who like making these videos and today we are going to
15:53:37
solve a lead code problem called generate parenthesis. Now if we see some of the popular companies who have already asked this question, there are
15:53:42
companies like Amazon, Facebook, Microsoft, Apple, Bloomberg, Uber, Lyft, Google, Ban, Spotify and Nvidia. So
15:53:51
that's why I'm paying my utmost attention. I hope you also enjoy the video.
15:53:56
Okay, so this is a lead code medium problem and also a very well-liked problem on lead code. Basically, we are
15:54:01
given an input number n and now we need to generate n pairs of parentheses. So basically we need to write a function
15:54:07
that generates all the possible combinations of well-formed parenthesis. Now these round parenthesis I think they
15:54:13
are called well-formed parenthesis. Now we can try to understand these two examples but I'm actually going to take
15:54:19
take it one step further and I'm going to show you four different examples to understand that what this problem is asking us to do. Okay. Now in this first
15:54:27
example we are basically given n is equal to one pair which means we need to make one possible pair and all the
15:54:32
combinations of this well-formed parenthesis. So obviously the answer is going to be quite simple. We simply need
15:54:38
to return like uh just one possible pair that we can make out of this one. Now suppose n is equal to 2. So now for n is
15:54:44
equal to 2 we have the choice to take like two of these and two of these right
15:54:49
we need to take four values. Uh so basically the number of possibilities we
15:54:54
can make is that we can actually make a parenthesis that looks like this and we can also make a parenthesis that looks
15:55:00
like this. These are the only two possibilities we can have and uh this is what we need to return as the answer.
15:55:06
Now things becomes a little bit interesting when we reach 2 n is equal to 3. Uh so when we get to the point
15:55:11
where n is equal to 3 the possibilities we can make is so these are the five possible pairs we
15:55:18
can make when n is equal to 3. Now notice that over here for every single piece we are using like three opening
15:55:24
brackets and we are also using three closing brackets but we are just putting them in different pairs so that they
15:55:30
generate like the well-formed parenthesis. Uh same way if we try to do it with n is equal to 4 the answer is
15:55:36
going to be pretty huge. So let me just uh draw it over here.
15:55:42
So these are all the possible pairs we can make when n is equal to four. And basically we are using four opening
15:55:47
brackets and four closing brackets and arranging them in different sizes. So this is a very interesting problem. Now
15:55:53
let's see that what are going to be the different approaches to solve this problem.
15:55:58
So now the first approach that comes to our mind is a brute force approach. In the brute force approach what we can do is suppose we are given n is equal to
15:56:04
two. Right? If we are given n is equal to two there is one thing guaranteed. We need to have four characters inside
15:56:10
every single block of our answer. Why four characters? because we are generating two pairs of parentheses. So
15:56:17
two pairs of parenthesis is basically going to be four characters at least. Right? So what we can do is uh now we
15:56:23
have two options to choose from. Either we can choose an opening parenthesis or we can choose a closing parenthesis. So what we are going to do is basically we
15:56:29
can take every single possible pair that we can make of size four using these two characters and only the valid pairs we
15:56:37
put put them in the answer. So suppose we are given n is equal to two. What are the different pairs we can make? Let me
15:56:42
make just a few pairs. So these are just some of the few examples that we can make for four characters using like this
15:56:48
opening and closing par parenthesis for n is equal to two. And over here we only need to find the legitimate pair. So
15:56:54
okay we can find one legitimate pair and we can find another legitimate pair and I think this is going to be the answer that we need to return. So we will put
15:57:01
these two in the answer and then just return them. But if you see this brute force approach is extremely inefficient.
15:57:08
If we see like time complexity the time complexity goes sometimes into like 2 to the^ of 2 n something multiplied by n
15:57:15
just to check that whether the pair is valid or not and that is disastrous. So no one is going to accept that. So we
15:57:21
will have to find a way to do something better.
15:57:26
So what we are going to do is we are going to do things smartly. How we are going to do things smartly? First let's
15:57:31
define our p purpose. Our purpose is to generate two pairs of opening and two pairs of closing brackets and they has
15:57:38
to be well informed or valid. Now we need like two opening brackets. So that
15:57:44
is a given fact. We need two closing brackets that is also a given fact. Now there are some properties that we can
15:57:50
use at our advantage taking consideration the definition of being valid. Now what is the definition of
15:57:56
being valid? So basically if we are given n is equal to 2 there has to be uh two opening parentheses and two closing
15:58:03
parenthesis. So that is one definition. Second definition for being valid is that we can only put a closing
15:58:11
parenthesis if there exist an opening parenthesis before that. Again I'm
15:58:17
repeating myself. We can only put a closing parenthesis if there exists a closing parenthesis before that. we
15:58:24
cannot start our answer with a closing parenthesis because that wouldn't be the valid. Uh third third thing that we need
15:58:32
to consider is that we can only have that many number of open parentheses
15:58:37
that is equal to the number of n. Now you are saying that why am I repeating myself because this is going to be the
15:58:43
very important property that we are going to use. Uh so now once we know all of these things let's try to make some
15:58:49
smart decisions on how we can actually generate the answer for valid parenthesis. Uh basically we are given n
15:58:56
is equal to two over here. Right. Now we have option to choose like two opening parenthesis and two closing parenthesis.
15:59:03
So okay now what we are going to do is for our answer generation always we will
15:59:08
have to start with us an opening parenthesis. Right. Now we we created the opening parenthesis that starts with
15:59:15
this one. Now we are going to keep track of few values. First value we are going to keep track of is the number of
15:59:20
opening parenthesis. Right? So number of opening parenthesis that we have used so far is one. Uh and what is the maximum
15:59:27
we can use? Maximum we can use is two because that is the value of n. We are also going to keep track of the number
15:59:33
of opening parenthesis we already know that is one. Right? We are also going to keep track of number of closing parenthesis. And so far we haven't used
15:59:40
any closing parenthesis so that this value is zero. And we can only add a closing parenthesis if the number of
15:59:48
opening parentheses is greater than the number of closing parenthesis because we already proved that over here. Now using
15:59:54
this logic let's see that what is the sequence we can make. Okay. So first we start with this value. When we start
16:00:00
with this value number of opening parenthesis is one. Number of closing parenthesis is zero. Now over here we
16:00:05
have two options. And those two options are we can either add one more opening parenthesis or we can add a closing
16:00:12
parenthesis. So let's see options in both of both of the cases. The number of opening parenthesis is going to be two
16:00:18
and we can have this value to be two because we are given n is equal to two and in this case the number of closing
16:00:24
parenthesis is still going to be zero because we have only used two open gap parenthesis over here. Now in this case
16:00:29
the answer is going to be a little bit different because the number of opening parenthesis is going to be one and number of closing parenthesis is also
16:00:35
going to be one and this is also valid. Why? Because the number of closing parentheses can be one because we
16:00:41
already had one open parenthesis. So so far both of the cases are legitimate. Now again at this position we also have
16:00:48
two more choices. So over here we have the one choice to open and we have one choice to close. Now let's see both the
16:00:55
options. If we try to go one choice to open, what will we will happen is number of opening bracket is going to be three.
16:01:01
But that is not valid. Why? Because we are given n is equal to two explicitly. So in this case we cannot go down this
16:01:07
path. So if we cannot go down this path we will actually backtrack and come back to this position. Now from this position
16:01:14
we can only go towards the path of closing. So if we go towards the path path of closing so far the number of
16:01:20
open brackets we had is two and the number of closed bracket we had is one. So that is still valid. That is still
16:01:26
legitimate. Now again from this position we still have two options. We can either open or we can close. If we try to open
16:01:32
we cannot do that because number of open is going to be three. So we are not going to go down this path. Uh if we go
16:01:37
down this path basically the number of open bracket is going to be two. Number of closed bracket is going to be two as
16:01:43
well. And this is the exact condition we need because we are given n is equal to
16:01:49
two. So which means that there has to be two open brackets and two closed brackets. So we can put two conditions
16:01:54
whether we can put like the combination of open plus close is going to be four that is going to be the double of what
16:01:59
is n or we can have like o is equal to 2 and c is equal to 2 both of them equal
16:02:05
to two. So this is also good. So now we have reached this condition which means that whatever the path we actually make
16:02:13
can make our ourselves into the answer. So what is the path we took? So first we
16:02:18
started with uh taking the opening bracket then again opening bracket then again closing bracket and then again
16:02:24
closing bracket. So let's put this value in the answer right. So we are going to create a new variable answer over here
16:02:30
and over here let's put one entry that okay two open two closed that is good. Now let's start following the other
16:02:36
path. I'm going to clean this up a bit so it does not become any more distraction. So now in this case okay
16:02:43
currently we have one open bracket one closed bracket. Now again we have two possibilities. So first possibility is
16:02:48
we can open one more bracket or we can close one more bracket. Now let's analyze both the possibilities. If we
16:02:54
try to open one more bracket basically the number of open brackets we are going to have is two. Let me clean this up a
16:02:59
bit more. And over here uh number of closed bracket we had so far is still one. So okay this is valid. We can put
16:03:06
this one. Now if we try to put one more closed bracket the number of open bracket we have so far is only going to
16:03:12
be one. But number of closed bracket is going to be two which is no a big no no. Why? Because we cannot have more closed
16:03:18
bracket than the number of brackets we have opened because that would defy the possibility of having a legitimate
16:03:25
scenario. So we cannot go down this path. So we won't. And uh now again we have two choices at this position. We
16:03:31
can open one or we can close one. If we open one then the number of open is going to be three. That is not valid.
16:03:37
That is not good. So we are not going to do anything with this one and we will not go down this path. If we go down
16:03:42
this path then over here number of open brackets we have so far is two and number of closed bracket we have so far
16:03:47
is also two which is also the legitimate scenario. So which means that this path is also going to be a path that we can
16:03:54
add to our answer and uh let's see okay so currently we have okay we have one
16:04:00
open bracket one closed bracket we also have one open bracket and one closed bracket and that's it. Now uh initially
16:04:07
remember we only started with this one opening bracket and then we had two possibilities and we actually exhausted
16:04:12
both the possibilities. So we cannot go down further anymore. Now because we
16:04:18
cannot go down further anymore uh we can conclude that whatever the values we find so far this is the complete answer
16:04:25
and we can return this as the answer and basically this is the whole crux of the finding the optimal solution. Now you
16:04:31
must be asking that hey what we actually did was we did something sim very
16:04:37
important. First we identify okay the one value then we had the final case. So
16:04:43
final case was that whenever the number of opening is equal to n and number of closing brackets is also equal to n.
16:04:48
This is our final case. And then at every single position we had two options to either choose an opening bracket and
16:04:54
closing bracket and keep on repeating the same process until we reach to the end and we had some parameters in mind.
16:05:02
So if you see we are actually using dynamic programming at its finest
16:05:07
because at any single previously computed value that is being used to calculate that which path we need to
16:05:13
take and whether we can take that path or not. So we are basically using dynamic programming plus backtracking to
16:05:20
solve this problem and this is going to be like an amazing way to explain this
16:05:26
problem. Uh logically think that in the brute force what a disastrous result we
16:05:32
were having and we actually brought it down to such like beautiful answer and then we are just presenting it. So this
16:05:38
is the whole power of uh using any like computer language.
16:05:46
So before we start implementing this generate parenthesis method, first we are going to create our backtrack method. Uh that is going to be our
16:05:52
helper method that we are going to use recursively. Now for the backtrack method, it is not going to return
16:05:58
anything. uh but it is going to add all the values towards the answer and uh inside the method we are actually going
16:06:04
to create a list of list that is going to store the answer. We are also going to have a string builder to keep track
16:06:10
of the current values we have the number of opening and number of closing brackets and also the maximum number of
16:06:16
values we can generate. Okay. So now first let's create the acceptable
16:06:21
scenario. So if basically the current length is actually going to be maximum *
16:06:26
2 uh which means that we can actually we have reached to our answer and we can add it to our answer. So this is the
16:06:34
legitimate scenario. Now let's see say for an example we find out that uh uh
16:06:39
the we have not reached the answer. Then what could be the possibility? Well, first possibility could be the number of open brackets uh that could be less than
16:06:46
the number of maximum brackets that is allowed. If that is the case, basically for the current uh string builder, we
16:06:53
can actually append an opening bracket. So let's do that. And uh after adding
16:06:59
the opening bracket, basically we will have to call the backtrack method again with a reduced value of one open
16:07:05
bracket. So let's do that. So in the backtrack method, we are going to call the answer and we are also going to call
16:07:11
the current uh string builder list we have. But for the open we are actually going to add one value. And for the
16:07:18
number of closed brackets we are going to keep it as it is. The max is also not going to be changed. And that is
16:07:24
awesome. Now there is also one more important thing we will have to do every single time we make a backtrack call and
16:07:30
that is to delete one character that is located at the current length minus one
16:07:36
because it is going to add an extra character. So let's do that.
16:07:42
Okay. Now same way uh say for an example if the number of uh closed brackets and
16:07:48
they are less than the number of open brackets. Uh if that is the case basically we can also add one close
16:07:55
bracket to our self as well. So let's do that and we are also going to call the backtrack method and uh everything else
16:08:02
is going to remain the same and basically this whole logic sums up our
16:08:07
backtrack method. Now all we need to do is from our main method we simply need to create a list of list called answer.
16:08:14
So let's do that and then we are going to call our backtrack method. Now inside
16:08:19
the backtrack method we are going to provide the value of answer. We are also going to provide a new instance of a
16:08:25
string builder pro going to provide the number of opening brackets that we have used so far is zero. Number of closing
16:08:31
brackets is also zero. And the maximum number of opening and closing bracket we can have is going to be the value of n.
16:08:38
And after getting the answer from the backtrack method, we can simply return the answer to be uh return the answer
16:08:44
that we got. And uh basically that's it. Yeah, let's try to run the code.
16:08:50
Okay, seems like our solution is working as expected. Let's try to submit the code.
16:08:56
If we submit the code, our solution beats lot of other solutions. It is really good in terms of time complexity
16:09:02
and it is also really efficient in terms of space complexity as well. So yeah, I'm going to be very satisfied with the
16:09:07
approach and uh now I will be posting the solution in the comments so you can check it out from there. Thank you.
16:09:21
Hello friends, hope you are having a fantastic day today. So once again we are going to do an awesome lead code problem that is really popular amongst
16:09:27
tech companies for the interviews. So without any delay, let's get started. So the lead code problem we are going to
16:09:33
solve today is called longest valid parenthesis and you can see that this one is a lead code hard problem and also
16:09:40
an extremely well-like problem on lead code. The problem statement is actually quite simple where we are told that we
16:09:46
are given a string that contains just the characters opening uh circular
16:09:51
bracket and closing circular bracket. And now we need to return the length of the longest valid parentheses substring.
16:09:59
Suppose we are given a string uh like this. Now we can see that all of these
16:10:04
are actually valid substrings because they are coming in correct order. So in this case since all of them are correct
16:10:11
we can say that the longest sub substring that is valid is currently of six characters. Same way let's try to
16:10:17
take one more example. Suppose the string we are currently given is something like this. then we only have a
16:10:24
valid valid substring that is only valid for just two characters and these two are not part of the valid substring. So
16:10:30
okay so we need to calculate that what is the consecutive longest valid substring and we need to return that.
16:10:40
Now brute force approach logically we are going to do the most simplest things possible where we are simply going to
16:10:46
check that for every single substring from starting from any particular string
16:10:52
we are going to check that what are the longest substring we are able to generate until we encounter some invalid
16:10:57
substring. So overall this approach is a very simplistic approach that would work
16:11:03
fine and generate the result but the issue is this would operate in big of n square time. So we need to find some way
16:11:10
to shorten this calculation and in a single go we need to identify that what
16:11:16
are the current substring that we have been able to find is it valid or not and
16:11:22
if it is valid what is the current length what is the maximum length we have been able to identify and
16:11:28
subsequently when will at what point does it stop becoming valid. So these
16:11:34
are the questions we will have to answer uh and then only we can find the optimal solution. So now let's start looking
16:11:40
about that what an optimal solution should look like.
16:11:46
Suppose this is the string given to us as an input and now we are trying to find the solution. Now let's try to make
16:11:54
some understanding clear and that would help us build our solution. Number one thing is the moment we identify at any
16:12:01
given moment that there is a closing circular bracket and we haven't found
16:12:06
the opening circular bracket which means we can directly ignore this case because this is definitely invalid because it
16:12:13
does not have any previous opening curly bracket. That is number one observation. Number two observation is for any single
16:12:20
opening curly bracket we will need to keep this information stored somewhere
16:12:25
that we have one open bracket for which we are trying to find a subsequent closed bracket. So it can come over here
16:12:32
or maybe here or maybe it cannot be possible but we will need to have that information. So these are the two pieces
16:12:38
of information we will have to consider. Third thing is it could be possible that we may find some existing valid uh
16:12:47
sequence like this but this may not be the longest valid sequence because
16:12:52
longest valid sequence in this case is probably going to be this one. So which
16:12:58
means we will have to keep track of the current sequence and we will also have to keep track of the valid sequence and
16:13:04
also the longest sequence. Considering all of these things, it would make really good sense to use stack data
16:13:12
structure for this problem. And why are we using stack? Because if if we have to
16:13:17
consider this to be valid, then immediately before this, there has to be an open bracket. Then only we can say
16:13:23
that this is a valid scenario. And then this bracket would not be considered, which means this still needs to live
16:13:29
inside the stack because stack follows an awesome property of last in first out. That is going to be greatly helpful
16:13:35
to us. So now using stack we would be able to solve many different problems
16:13:41
and the idea is that for each of this position rather than just storing whether it's an open or curly bracket we
16:13:48
can actually store the index values. So let me write down the index values. And now the thing is inside the stack we
16:13:55
will only push values when we encounter some open bracket because it could be
16:14:01
possible that sometime in the future there might be a closing bracket. So and whenever we identify a closing bracket
16:14:07
we will try to see in the stack that whether there exist any particular
16:14:12
bracket that we can pop out. If it does then it would be part of the valid sequence. If it is not there then we
16:14:19
will see all sorts of scenarios. Okay. So I hope that all of these explanation make sense and now you are able to
16:14:25
understand that how we are actually going to use the stack for our solution. So let's quickly generate the stack. Now
16:14:32
we are going to keep track of few variables. So first one is that what is the current length we have been able to
16:14:39
find. Next what is the maximum length we have been able to achieve. Now in order to keep track of the current length we
16:14:46
will have we will need to know that where does the current valid substring starts. So initially because we are
16:14:53
actually using this as zero. So initially our starter pointer needs to be somewhere over here before zero
16:14:59
because we are starting the index from zero because imagine a scenario where we are only given an input like this which
16:15:05
means this is 01. So based on the index location we know that this is actually a valid substring of size two but because
16:15:12
we are starting the index from zero so we will actually create our initial starting pointer from minus one. So it
16:15:18
would be very convenient for us to calculate these values. Okay. And you will understand the logic once we
16:15:24
iterate over the the example. So initially our starting pointer is going to be located at minus one position and
16:15:32
this is where our starting pointer is. Okay. So now let's quickly start iterating over the solution. So
16:15:39
logically first here we identify that this is a closing bracket. For closing
16:15:44
bracket we will have to pop one element out from the stack. But the thing is currently stack is empty. So because
16:15:50
stack is empty, this has to be an invalid entry. So we can ignore this
16:15:56
case and move on to the next element. But when we move on to the next element, we can say for sure that this is never
16:16:02
going to be part of the uh valid substring. So we will need to update our
16:16:08
start pointer. So now we will have our start variable uh being located at
16:16:13
position number one. So let's just mark our start variable at position number one. current length is zero and maximum
16:16:20
length is also zero. We haven't been able to find any values. Okay, so let's just mark these. Now we encounter an
16:16:26
opening bracket. So the moment we encounter the opening bracket, we are going to be pushing the values inside the stack. So let's mark the index
16:16:33
value. Same way once again we identify an opening bracket. So once again we are going to mark a value inside the
16:16:38
bracket. And when we are opening the brackets, we don't need to update the current length or the maximum length
16:16:44
because we haven't find any valid substring so far. Okay. Now we identified one closing bracket. So the
16:16:51
moment we identify a closing bracket, we will have to pop element out of the stack. So let's try to pop one element
16:16:59
out of the stack. If we pop this element out of the stack by the way, this is this has to be number two. Okay, by the
16:17:05
way, so number two index we are popping out of the stack. Which means that
16:17:11
currently there what has been the current length we have been able to identify it so far. That is currently we
16:17:17
are at element number three. The element we popped out is located at element number two. Which means now this is no
16:17:24
longer present over here. Which means currently we still have one element that
16:17:30
is left inside the given stack. So so far we can do the difference between
16:17:35
this current element and the element that is already present inside the stack using the peak function. So the
16:17:41
difference is 3 minus one. So so far we have been able to identify a length of
16:17:46
two size valid string. So let's update the value that the current valid string
16:17:52
that we have been able to find is of size two and the maximum length we have been able to identify so far is also of
16:17:59
size two. Now notice that we are not using the start variable right here. Uh
16:18:05
because this is still not taken care inside the existing valid substring. So
16:18:11
that's why as long as there are some values present inside the stack. We cannot conclude that stack is empty and
16:18:18
we have taken care of every single substring. So that's why start pointer is still going to remain here. So now
16:18:24
let's move on to the next element. Now we are at position number four. Once again we identified the opening bracket.
16:18:30
So let's try to add one more value inside our existing stack. So now the
16:18:35
value is four. Okay. Now once again we identified a closing bracket. So what the moment we identify a closing
16:18:41
bracket, we will have to pop one element out. So let's quickly pop this element out. Now the element that is currently
16:18:48
left inside the string is of size one. So because this is of size one and the
16:18:54
current element vr is of size five which means the current substring that we have been able to find is 5 minus one. So
16:19:01
this is going to be uh four. So current length that we have been able to find the current maximum length is of size
16:19:08
four. And because this is of size four which means we will also have to update our maximum length as well and that is
16:19:15
also going to be of size four. Okay. Now currently inside our stack we only have
16:19:21
uh one element that was that has been here for quite some time and now let us
16:19:26
also try to move to the next element. So once again we identified one more opening bracket. So we will try to put
16:19:32
element number six inside the bracket. Now once again we identified the opening bracket. So we will try to put element
16:19:38
number seven inside the bracket. And now at element number eight we identified
16:19:43
and by the way this current length would be reset uh reset every single time we update the value. Okay. So this is
16:19:50
always going to be reset because we don't know that what the current length is. We only define the current length
16:19:55
based on the value we pop out. So now this is a closing bracket which means we will have to pop one element out. So now
16:20:01
we are located at value number eight. We popped element number seven out which means we still have one more open
16:20:09
bracket located at element number six that we haven't taken care of. So now we will do the difference between 8 - 6 and
16:20:16
the value is 2. So current valid length that we have been able to identified is of size two but that is not greater than
16:20:23
the maximum length we have been able to achieve. So we are still going to mark this as value number four. So this is
16:20:29
the logic on how you can actually use stack to solve the problem. Now let me just show you one more example very
16:20:35
quickly uh and then we will uh move to the coding solution. Basically this is the optimal solution. So now let's just
16:20:42
quickly start using the logic. So currently we identify an opening bracket. So we are going to mark value inside the stack. We once again identify
16:20:49
a closing bracket. So once again we are going to pop this element out of the stack. The moment we pop this element
16:20:55
out of the stack and currently the stack is empty. If the stack is empty then we will have to we found a valid string
16:21:02
from the starting value. So we are going to do the subtraction between the current value minus the starting value
16:21:08
which means 1 - -1. So the answer is going to be two. So the current length
16:21:14
that we have been able to identified is two and the maximum length we all we also identified is also two. Okay. Now
16:21:20
once again so far remember this uh s is the starting value is still going to remain here but now we identified a
16:21:28
closing bracket but for this closing bracket we don't have any value inside our stack. So because the stack is empty
16:21:34
which means this is an invalid portion. So now the starting value has to jump. So now we are going to jump our starting
16:21:40
value to start at this element number three. Okay. Now this at this element number three we identify an open
16:21:47
bracket. We are going to add value number three over here. Once again for four we identified a closing bracket. So
16:21:52
we will pop an element out of the loop. So currently the stack is empty. If the
16:21:57
stack is empty so now we are located at this position number four. And by the
16:22:02
way our starting position should be at this position number two. Okay. So now
16:22:08
currently we need to because stack is empty we will need to do the difference. So the difference between uh current
16:22:14
index and starting index is going to be 4 minus 2. So value is two. So that this
16:22:20
is the current length we have been able to identify and this is for this portion. So now maximum length does not
16:22:26
need to change. Once again we identify an open bracket. So we are going to add value number five over here and once
16:22:32
again we identified a closing bracket. So now we will have to pop this element number five from the loop as well. So
16:22:37
currently the string is empty. Because the string is empty we will have to do the current value minus x. So it's going
16:22:43
to be 6 minus 2. So once again the current length we have been able to identify it is four. So the current
16:22:49
length needs to be updated. This is going to be four. And because this is greater than our maximum length. So we
16:22:55
are also going to update this one. And because we reached to the end of this given string so we can return the
16:23:00
maximum length as four. So this is the whole logic that we can use to solve this problem. And by the way if we see
16:23:06
time complexity in this case the time complexity is going to be simply big of n because we are simply iterating the
16:23:12
given input array just once. If we see space complexity because we are using an extra stack we will it will also going
16:23:18
to be big of n. So the coding solution is actually quite
16:23:24
simple. First we have a variable to store the maximum length. Then we initialize our stack and then we
16:23:30
initialize the first value inside the stack as minus one. This is going to be our starting pointer. Okay. Then we have
16:23:36
our for loop to iterate over the given string s character by character. We check that whether the given string if
16:23:43
that is an opening bracket or a closing bracket. If it is an opening bracket, we simply push that index position into the
16:23:49
stack. If that is not the case, then there can be couple of scenarios. So in either scenario, first we will have to
16:23:56
pop the element out of the stack. Now after popping element out of the stack, if the given stack is empty, then we
16:24:03
need to push the current index as the base for the next valid substring. And
16:24:09
uh if that is not the case then we are going to calculate the maximum length. So for maximum length we are simply
16:24:15
going to do the max to compare the current maximum length minus i minus the
16:24:20
peak that is currently present inside the stack and this is going to be give you give us the current length that we
16:24:27
are dealing with and in the end we simply need to return whatever the max length we have been able to identify. So
16:24:32
let's try to run this code.
16:24:38
Okay, seems like our solution is working as expected. Let's submit this code
16:24:44
and our code runs extremely fast and this is a very good time and space complexity. So once again I will be
16:24:49
posting this solution in the in our GitHub repository. So you can check it out from there. The link is in the description. Thank you.
16:25:03
Hello friends, hope you are having a fantastic day today. So once again we are going to do an awesome lead code problem that is extremely popular at all
16:25:10
sorts of IT companies. So without any delay let's get started. So the lead code problem we are going to solve today
16:25:16
is called largest rectangle in a histogram. This is a lead code hard problem and also an extremely well-like
16:25:22
problem. Now the statement is quite simple and straightforward. We are given an array of integer called heights that
16:25:28
represent the histogram's bar height. And we are also told that the width of every single bar is one. Now we need to
16:25:36
return the area of the largest rectangle that we can make inside this given histogram. So this is all we need to
16:25:43
return. And now let's try to understand this with an example. So for this we can make a rectangle that looks like this.
16:25:49
Now the area of this rectangle is going to be two because the width of this portion is 1 and the height of this
16:25:56
portion is 2. So 2 * 1 is going to be two. So same way there are multiple different options we can have in order
16:26:02
to generate the area. But we need to find the maximum area. And in this case the answer would be retrived using these
16:26:09
values where if we make a rectangle like this using these two bars. So now in
16:26:15
this case the area is actually going to be 10. Why? because the height of this
16:26:20
portion is five and for this one the width is 2. So 2 * 5 is going to be 10.
16:26:26
So this is what we need to find and this is what we need to return.
16:26:31
So brute force approach is actually quite straightforward and very simple. Now one thing we can do is that we can
16:26:38
take this one single rectangle uh starting at position zero and then we
16:26:43
can see that what are every single possible areas we can make. So one area would be like this. Second area would be
16:26:50
like this. The third area would be something like this. Uh fourth area
16:26:56
would be something like this. And so on and so forth. And eventually we do all
16:27:01
every single possible combination based on every single position of the
16:27:06
given rectangle bar height. And then eventually we would find a solution like this that contains the most optimal
16:27:13
approach. And this solution would work fine. we would be able to eventually find the answer but this is going to
16:27:19
work in big of n square time because it every single time we are doing lot of extra and overhead work.
16:27:28
So what is the most common thing we can imagine? Well, number one observation we can make is because we can see that the
16:27:35
height for this zero index is two at the moment. But the moment we want to
16:27:40
consider this first index as in combination with this two then the
16:27:46
maximum height we can imagine is only going to be equal to one. Which means we
16:27:51
are only at the higher height until we encounter a height that is lower than
16:27:56
our current height. And whenever that happens, we will have to start considering the lower height and we need
16:28:02
to understand couple of things. If we want to calculate the area, we need two
16:28:07
items. First item is the height. So we already know that which height are we
16:28:12
going to consider based on the lower height compared to all the other possible heights. That is uh number one
16:28:19
observation. Second observation is we need to consider the width. So, so width
16:28:24
we can simply calculate based on the current index position where we have or we can also keep track of that where did
16:28:32
that height started existing that in terms of finding the right side boundary
16:28:38
of any particular rectangle we can only find it until we find a lower height
16:28:44
that reaches. So there are actually three examples we can see very easily.
16:28:49
First example is at this position number two or this uh initial first position
16:28:54
where the current height is two and the current height is located position number zero. But the moment we try to
16:29:01
consider the next element we will have to get rid of this height two because now it is no longer in the existence
16:29:06
which means the maximum area we are being able to generate using this bar two is only going to be two. Okay. Now
16:29:13
next thing another example is we just saw with the value number five that with
16:29:19
value number five we can only say that we can use rectangle five or bar five
16:29:24
until we reach to this index position number four and then so which means maximum area that this bar five can make
16:29:32
is going to be of width two and height five. So total is going to be 10. Same
16:29:37
way for this six. Six comes into the existence at index number three. But
16:29:43
since the height at index number four is actually lesser than the index number three which means this six only remains
16:29:50
in existence just for one single bar. So the maximum area we can make over here
16:29:55
is al is only going to be of size six. And this is the whole logic. This is the
16:30:01
whole meat of the solution. Now after understanding this we can actually make a suboptimal solution using the same or
16:30:09
very simple approach and then we will try to improve upon that solution. So the sub suboptimal solution that I'm
16:30:16
proposing is that at every single position we identify that what its right
16:30:21
side boundary is and what its left side boundary is. So what is the maximum
16:30:26
height and width we can make and based on that we can do all sorts of calculations and then find the solutions
16:30:32
very quickly. So let's try to see this solution in exist in action. The idea is
16:30:38
at this position the maximum left side height we can make is two. The maximum right side height we can make is also
16:30:45
going the maximum width we are able to achieve is one. Which means the maximum area we can generate is only going to be
16:30:51
two. For this position number one, the maximum width we are able to achieve is
16:30:56
going to be six because this one remains in existence throughout this whole process. And the maximum height we can
16:31:03
achieve is only going to be one. So over here, maximum area we can make is only going to be six. Now at this five, the
16:31:10
maximum left side we can go is only up to two because it starts at position
16:31:15
two. The maximum in terms of right we can go is only up until position four or
16:31:21
before position four. So up to two and three. So width is going to be two. So over here we can make the area 10. For
16:31:28
this height six we can only make the maximum height as six. Same way at this
16:31:33
position number two. The maximum we can make is actually going to be this much where currently the width is going to be
16:31:41
four and the height is going to be two. So maximum area we are able to generate is eight and same way at this three the
16:31:48
maximum we are able to generate is simply going to be uh just just this one
16:31:54
because one before that is actually in the lesser height. So we can maximum area we can make using only or or the
16:32:02
entire height of this area is going to be three and in the end we can simply return 10 as the answer. So what we did
16:32:09
is for every single element we try to see that what is the left limit, what is the right limit and what is the total
16:32:15
area we are able to generate and then we can very easily store the answer. Now this solution would just be good if you
16:32:23
provide this solution in an interview. It might even work. But the thing is there exist a better solution where if
16:32:30
we just use stack to keep track that what is the current index position and
16:32:36
until what previous index positions we are maintaining that height then we can very easily solve this problem.
16:32:45
Why we need to use the stack? Because think about it, for every single position, we are only going to have that
16:32:51
position in existence until we find another bar with a lower height. Which
16:32:57
means the moment we find another bar with a lower height, we can actually go
16:33:02
back to the elements that are already present inside the stack with the higher height and calculate the area. That's
16:33:08
it. That is the whole logic. So now let's try to see the solution I'm proposing in action. So now let's just
16:33:16
quickly initiate our stack. Now inside the stack we know that this is going to
16:33:21
operate in the in terms of last in first out principle and one the other thing is
16:33:28
we can actually keep track of the bar heights but then we would also have to find that what was the initial position
16:33:34
of that this particular value. So rather than a better approach is that we actually store the index values and
16:33:40
using the index values we can quickly look up that what has been the bar height at that position in big go of one
16:33:46
time because we already know the index position and then we would be able to also calculate the width depending on
16:33:53
the current index position and the existing index position inside the stack. So let's try to see the solution
16:33:59
in action. So initially stack is empty. Okay. And we are also going to have a
16:34:05
variable where we are going to store the area. So let's just mark this one as max max area that we have been able to
16:34:11
calculate so far. Okay. So initially stack is empty. Now we are at this index position number zero. So we add index
16:34:18
position zero inside our stack. Okay. And currently we know that this height is two. Now next thing is we iterate
16:34:25
over to the next element and we identify that currently we are at index position one. So the height at index position is
16:34:33
actually less than the height we currently have on the element that is already present inside the stack. Which
16:34:39
means this position of this element two is no longer relevant because we found
16:34:46
out a value that is lesser inside the in in its existence which means this only
16:34:51
exist until this portion. So we will try to we will pop this element out and we
16:34:56
will calculate the possible area that is that this element has been able to generate. So currently for this first
16:35:03
position this has been the area it is able to generate that area is going to be two that is the height and multiplied
16:35:09
by width that is one. So the maximum area we have so far is two. Okay. Now
16:35:15
once again we are going to add value number one inside our stack saying that
16:35:20
currently one. So the the height of this one is also one and currently we we will
16:35:26
only pop one out when we either reach to the end of the array or so or end of the
16:35:32
heights or we find some place where the height is actually zero and then we have some more elements. Okay. So this is
16:35:39
always going to be relevant in this example. Now we are at index position number two. So notice what happened at
16:35:45
index position number two. The height suddenly increased compared to what the height we already have. which means this
16:35:52
one is still valid. So because it is still valid we are going to keep it inside the stack not popping it out and
16:35:59
we will add one more element five or the this index position two on top of the
16:36:04
stack because now this is also relevant so far. So we are going to put two inside the stack. So it subsequent value
16:36:11
is bar height five. Then we are next we identify height six which means this
16:36:16
five is still relevant. So because five is relevant we are once again going to add value number six on top of the stack
16:36:23
or sorry not value number six but the index position of six which is value number three. So we put value number
16:36:28
three inside on top of the stack and the height is six. Now we suddenly encounter
16:36:34
the value at index position number four that is height two. So any single value
16:36:41
that has greater than two height has to be popped out of the stack because now
16:36:46
that is no longer relevant. Which means first of all this six is now no longer going to be relevant because the height
16:36:52
is six and currently this index position is three. And notice that the index position for this bar height 2 is four.
16:37:00
Which means depending on the index position difference we can actually calculate the width for which this six
16:37:06
was relevant. So six was currently relevant for width one. So currently
16:37:11
let's pop six out. If we pop six out, currently this three is no longer present. We know that this was relevant
16:37:17
for one width which means width was one and the height was six. So now the maximum rectangle we have been able to
16:37:24
find is of size six which is greater than the previous maximum we had. So we are going to update that. Okay. Now are
16:37:30
we done? No. Because this is two and this value is five which means we would still have to pop one value out. If we
16:37:36
pop one value out in this case. Now notice that the height at this position is two and the height at this position
16:37:44
is four. So because this is a greater position compared to over here. So what
16:37:50
is the width we found? The width is actually two. And what is the height we
16:37:55
have is five. So this is the height. And also let's get rid of this two from our
16:38:01
existing sack. Okay. And now this area is going to become 10. So let's just add
16:38:06
an area 10. Now once again we this we have this element one and currently this
16:38:12
element is two. So two is greater than one. So because two is greater than one we are not going to pop one out because
16:38:19
this one is still relevant. So we are just going to simply add two on top of
16:38:24
one. So let's just quickly add this index position number four with the height two. Okay. And now currently next
16:38:32
one we found the increase inside the height which means this two is still relevant. Because this two is relevant
16:38:38
we are simply going to add an element five on top. So we are going to add element five on top. Now adding index
16:38:46
position number five. Now we reach to the end of the array which means the moment we reach to the end of the array we will have to start popping every
16:38:53
single value out compared to its current position. So currently we pop value
16:38:58
number five out which means what is the height over here? The height is three. What was what would be the width? Width
16:39:04
would only be one because it is only relevant for this one portion because currently we are at the end of our loop.
16:39:10
So the area we have been able to calculate by popping this uh value number three out is going to be three.
16:39:16
Now currently three is less than value 10 which is the maximum area we have. So
16:39:21
we are not going to update the maximum area. Okay. Now we are going to next pop out element number four. So if we pop
16:39:29
element number four out it has been relevant for this much portion of the time which means currently we have 2 *
16:39:35
2. So the area is going to be four. Four is also less than 10 which means this area is also not relevant. And last one
16:39:42
we will have to pop element number one out that has the size one or the height one. So for this height is going to be
16:39:49
one and this has been relevant since position one until the very last position. So this has been relevant for
16:39:56
the width five. Oh sorry for the width six since the very first position it has
16:40:01
been relevant. So now because this has been relevant since position six. So the
16:40:07
maximum area we have been able to generate is also going to be six. But still it is not greater than the maximum
16:40:13
area. So after the end of this loop we can simply return the max area to be 10 and that's it. That's the whole answer.
16:40:20
Now if we see time and space complexity in this case the time complexity is going to be big of n and the space
16:40:25
complexity is also going to be big of n.
16:40:31
So the coding solution is actually quite straightforward. First we have a variable called max area where we are
16:40:36
going to be storing the maximum area we have been able to identify so far. Then we have our stack that we initialize and
16:40:42
we also have a variable n the for the to store the length of the given array.
16:40:47
Then we have our for loop to iterate over the given array. Now first we check for a condition that if the if the given
16:40:54
i is equal to n which means we have already crossed every single element
16:41:00
then we can mark the current height as zero because this is to take care of the last element. If that is not the case,
16:41:06
we simply take the value of the given subsequent height height from the heights array. Okay. Now we have our
16:41:13
while loop where we check that while the given stack is not empty and the current
16:41:19
height that we have been able to identify for any given E element is less than the current height that is already
16:41:27
present inside the very first element of the stack. Then we will have to
16:41:33
calculate the area for that. uh where we simply calculate the height based on by
16:41:39
popping the element out of the stack and then we calculate the width by uh
16:41:44
subtracting the value of the current I minus the current element that is that
16:41:49
was present inside the stack minus one and then we calculate the max area where we compare two elements based on the
16:41:56
given max area that we have been able to identify so far and the given current
16:42:02
height and width multiplication or the current area that we have been able to identify. Whichever is greater, we are
16:42:08
going to keep it that. And in the end, after we run out of this while loop, we are still going to push the current
16:42:14
element inside our stack. And by the time we are done with all the elements, we should have our maximum area being
16:42:20
populated with the correct value and then we can simply return that. So now let's try to run this code.
16:42:32
Okay, seems like our solution is working as expected. Let's submit this code
16:42:37
and once again our solution runs beautifully extremely fast in terms of time and space complexity. So once again
16:42:43
the solution is present in the GitHub repository. The link is in the description so you can check it out from there. Thank you.
16:43:02
Hello friends. Hope you're having a fantastic day today. So now we are going to do a full course on everything there
16:43:07
is to know about Q data structure. It is one of the fundamental data structures and also it has lot of massive
16:43:13
applications both in the real world and also it is very popular in technical interviews. So we will understand that
16:43:19
what is Q, how it is being used, what are the different operations it supports, how you can implement Q's and
16:43:25
then we will see that all the different popular most like most asked and most
16:43:30
important lead code problems that has been asked in tons of technical interviews. Q's goes well with lot of
16:43:36
other data structures such as trees and graphs and arrays and stuff like that. So we will understand it from that
16:43:41
perspective as well. So without any delay, let's get started. Now let's try to understand that how does Q work. Q is
16:43:48
a very simple linear data structure and we have all seen Q's in real life in
16:43:54
action. Basically let's say that if there is a bank teller who is providing their services and bunch of different
16:44:00
people wants to access these services. Typically they are going to form a set of que and this que is going to follow
16:44:06
the principle of simply first in first out. What is first in first out means
16:44:12
that whoever was the first person within the queue is going to be the first person eligible to receive whatever the
16:44:18
services that they are looking forward and once they get done with their services next person in line would come
16:44:24
in and again do the same thing. So if more people wants to enter the queue they are typically going going to enter
16:44:31
the queue in the back side of the queue. Meanwhile the queue is going to keep on ending from the front of the queue. This
16:44:37
is a slightly different data structure compared to the stack that we have seen before where stack typically operates in
16:44:44
last in first out principle. Meanwhile Q operates in the first in first out
16:44:50
principle and there is a difference on the stack both input and output typically operates at the same end
16:44:57
meanwhile the other end is always going to be sealed where nothing can happen. But in the queue where we are going to
16:45:04
have two ends typically where one end is the place where new entries would be entering within the queue and one end
16:45:11
would be the place where all the previously existed entries are going to come out in the FIFO fashion. So think
16:45:17
of it like a printer job in any particular company where there are hundreds of employees and a single
16:45:23
printer. So printer is going to print whoever requested first and then they would complete their job and move on to
16:45:29
the next candidate. So let's try to understand that what are all the different operations you can perform on
16:45:34
any given Q. Now I already told you that Q typically operates on two different
16:45:39
ends where we have one end where the stuff enters and one one end where the
16:45:45
stuff gets out. So let's try to understand that what are the different operations we can typically perform.
16:45:50
First operation is NQ. NQ means that we are inserting an element at the rare end
16:45:56
of a cube. So this is going to be the first place where element gets entered and if any new elements comes in
16:46:02
depending on the implementation essentially this element would move forward in the place. So this is going
16:46:08
to be x and let's say a new element y comes in then y would be typically entering once again at the rear end of
16:46:14
the cube. Now uh same way we can nq we can also dq. So dq means that we are
16:46:20
getting rid of the elements that are already present. So eventually let's say that this Q contains A B C XY and they
16:46:27
came in as the sequence of A B C XY. So A would be the first element to get DQed
16:46:33
if we do this operation. And once doing that essentially all of this cell is going to become empty and all of these
16:46:40
other previous cell would shift one place and then they would be part of uh the same Q where B would be the next
16:46:47
candidate if we have to dq within the B. Now what does there is one more operation we can do and that is called
16:46:53
peak or sometimes it is also called front. So this simply shows that whatever the value is currently present
16:47:00
at the very beginning of the cube. So in this case if we do peak operation we would fetch the value as B. Uh if we do
16:47:07
now same way there can be another operation called rear. So rear simply returns that what was the last element
16:47:13
that was added within the cube without removing it. And again this depends on the implementation but we can have a
16:47:19
functionality where we can some in some cases check for this results. Once again in the queue we can also do is empty uh
16:47:27
method. So this defines that whether the given que is empty or not. And same way we can do is full method as well. So
16:47:33
this defines that whether the given que is full or not. So both can be done uh with in any given qes.
16:47:41
Now let's try to understand the common Q implementations. So most common way to implement a Q is using an array. Now we
16:47:48
all know that how does an array looks like. It is typically a fixed size Q that is going to have one end where we
16:47:54
enter the stuff or where we encq the stuff and there is going to be a second end where we can dq the stuff. So in
16:48:02
this case there are some benefits and there are some discontinuations as well because if we add stuff at the rear end
16:48:08
if we have one more value we are going to add we will have to essentially readjust our existing array and then we
16:48:15
are going to have values like this. So if we keep on doing that for a bunch of different uh insert and delete
16:48:20
operations then in that case our whole system can basically operate for insert
16:48:26
in the worst case in big of one value or in the first iteration initial iterations the array might remain empty.
16:48:32
So because of the fixed size there can be some concerns but this is a common way to implement a que. Same way a
16:48:39
better op uh way to implement a que is a link list where we don't have to worry about uh the size being fixed or not
16:48:45
because it grows and shrinks dynamically. So we don't have to care about that. On top of it we always know
16:48:52
that uh we we are going to have our head that is going to point towards the first end or the first pointer that is
16:48:59
currently present within the cube and we are also going to have a pointer that is going to locate to the rear end of the
16:49:05
cube. So if we have a new element we want to add, we can simply add it at the rear end without worrying about much
16:49:11
about anything else and then we can just have it point to the null pointer and then mark it as the rear end or the last
16:49:18
element within the cube. And if we have to nq stuff out, we can simply go over the head of the cube and check out
16:49:25
whatever the first pointer is and then we can get rid of it and then have our head point to the new element. So nqing
16:49:32
and dqing becomes much more efficient essentially in big go of one time and this is going to be a much quicker way
16:49:39
because we are not worried about uh having a fixed size queue at any given moment. So there is better memory
16:49:44
allocation and faster way of enqing and dqing stuff. So in the most of the real world application we typically have
16:49:51
something like a link list that is always going to be implementing a que. Now there is also one more uh conceptual
16:49:57
queue that is a circular q. Essentially it's uh an array based implementation in
16:50:03
which case we are going to have a rear and front being close to each other or
16:50:08
next to each other and then we can start filling stuff from the front and we will keep on going on and on and on until we
16:50:14
reach to the rear and eventually the next element would be the front and if you have to remove stuff we will just
16:50:20
simply remove the stuff from the front position and then we will update the existing front position to the next
16:50:26
position available. So that's where we are going to essentially uh NQing and DQing stuff. So we are going to see a
16:50:33
problem that defines that how does a circular Q operates but it will give us
16:50:38
some idea. Now let's talk about couple of special Q's. First one comes to mind is called double-ended Q. So in simple
16:50:46
terms we also write it as DQ but don't get it confused with the DQ operation that we do. Okay. So let's understand
16:50:53
the concept. Double-ended Q means as the name suggest we do both the operations
16:50:59
that are insert and also removal at the both ends of the que. So in in simple
16:51:05
terms we can insert from both the ends and if we have to remove elements we can also do it from both the ends. Now in a
16:51:12
typical Q we simply follow the FIFO principle but in a DQ or double-ended
16:51:18
cube we can do it in both the both the places. Now we can be restrictive about some cases. If we want to restrict it
16:51:24
based on the input, we can say that input all only comes through one end but we can have output going from both the
16:51:31
ends that can be an option. Or if you want to become restrictive based off of output, we can say that output will only
16:51:38
happen through one way but input can happen through both the ways. So there are some variations around DQ or
16:51:44
double-ended Q. But more or less we have this implementation and we are going to see some examples of this. Now question
16:51:50
comes that why do we even need a scenario like this? Well, this is actually quite useful in many of the
16:51:56
typical lead code problems we are trying to solve something like sliding window approach or uh generating different
16:52:02
palendromes. Second one is called priority Q. Now this priority Q can also
16:52:08
refer to as heap sometimes. Now this is a very unique case because we use heap
16:52:14
in all sorts of places. Heap is an implementation of cube where we always
16:52:20
store either minimum value or maximum value on one end of the cube. So we can
16:52:25
have a cube that contains bunch of different elements. But when we are adding those elements uh let's say that
16:52:32
this is going to be a min cube. So we first try to add element number five inside it. Now currently this q is
16:52:39
empty. So five is the minimum value that is possible. So we can have five sitting over here. Then we are trying to add
16:52:45
another value three. But now three is smaller than five. So the very first element present within the cube has to
16:52:52
be three. And then the whole Q is going to be readjusted. Meanwhile, if we had
16:52:57
just followed the simple FIFO principle where then five would have been the first position in the queue and then
16:53:03
three would have been sitting next to it. But since this is a minimum heap that we are trying to maintain basically
16:53:09
we would have three come over here. So why this is being used? This can be helpful in all sorts of priority Qbaseda
16:53:16
cases where we have some weight associated with any kind of queue that we are trying to maintain. Now don't
16:53:23
worry about this. This is a very important concept. So we have created an entirely separate course on priority
16:53:30
cues and bunch of different examples of that. So we are going to be studying this in very much depth because it's
16:53:36
also one of the most popular topics at companies like Google and Amazon. So we will keep that in mind. Okay. Now we
16:53:43
have understood the basic principle on what Q is. Let's try to go over some most popular lead code problems that
16:53:49
would really solidify our knowledge on Q related data structure questions.
16:53:56
So the lead code problem we are going to solve now is called implement Q using stacks. This one is a lead code easy
16:54:01
problem and also very popular and important problem because we are tackling the core principle of two
16:54:08
different data structures in a simple problem. So let's understand that what do we need to do basically we need to
16:54:14
implement a Q data structure only using two stacks that is the whole pro purpose
16:54:20
and now we are given the definition that what operations do we have to support so first operation is push push means that
16:54:27
let's say that this is our current Q and current Q is empty now we all know the concept of the cube that we have stuff
16:54:34
entering from one end and going out from the other end mean where we are following the principle of first in
16:54:40
first out. So let's say that we first uh push an element three. So that three is
16:54:46
going to present within the que. Now we also push one more element within the queue that is five. So now we have two
16:54:53
elements living in the que that is three and five. And then we add one more element that is let's say one. So now we
16:54:59
would have three elements living that is going to be three, five and one. So now we have three elements within our cube.
16:55:06
Now next operation we'll have to support is pop. So if we pop one element out basically we would be popping three out
16:55:12
then we only have five and one present within the cube. Now next operation we need to support is peak. So peak means
16:55:19
that we are not popping the element out but we are checking that what is the first element that is eligible to get
16:55:25
out or at the top of the que. So in this case that element is going to become five. So this would have returned five
16:55:31
and last one is is empty. So currently our Q contains two elements five and one. So this is not an empty Q. So in
16:55:38
this case we would return false. Now the problem is stack only follows the last
16:55:43
in first out principle. So let's say that if I have given one stack and if I'm trying to enter value number five
16:55:50
over here, this five is going to reside over here. Then if I want to enter one more value one over here, this one is
16:55:56
going to reside over here. Now if I try to pop elements out and we are I'm going to be elim eliminating value number one
16:56:03
first before eliminating value number five. But in the actual real world where
16:56:09
uh if I'm trying to have a Q- like structure, I should have eliminated five. Now lucky for us, we are being
16:56:16
told that we can use two stacks to basically uh mimic a Q. So how we are
16:56:21
going to use two stacks? Basically, we are going to have one stack that is dedicated only for input or insertion
16:56:28
steps. So whenever we need to input any element, we are going to put in this stack. So let's just call it an in stack
16:56:36
where we are only adding the values. Same way we are going to have another stack dedicated simply where we have to
16:56:42
pop elements out. So we can call this an out stack. And now using this we can
16:56:48
actually implement Q very easily and very efficiently. So let's understand that what are the operations we will
16:56:53
have to support. First operation we need to support is push. Second one is pop. Next one is peep and last one is is
16:57:01
empty. Okay. So currently I'm not too worried about is empty operation because it is like a given fact. So we can check
16:57:08
it anytime. I'm more concerned about these three operations. So now let's try to see that how would this work in this
16:57:14
scenario. So let's say that our Q is currently empty. Now we need to enter element number one in the que. So we
16:57:21
were always going to insert things in the in Q. So now we have pushed element
16:57:26
number one. Next sequence is that we once again need to push element number five. So we are going to push element
16:57:32
number five over here. Now next sequence is that we need to push element number seven. So now we are going to push
16:57:38
element number seven over here. Now I want to do a pop operation. Now notice
16:57:44
that we always do pop operations through our outst but our outstack is currently
16:57:50
empty. So whenever we find that our outstack is empty but there are still
16:57:55
stuff available in our instack. So we are going to pop all the elements and
16:58:00
then we are going to dump them in the outst. Uh let me explain. So if I pop all the elements right now basically I'm
16:58:08
going to have seven sit over here then five sit over here and then one sit over here and this whole stack is going to
16:58:14
become empty. Now if I have more values that are going to be coming in that I
16:58:19
have to serve. Let's say that any particular entries such as 6 or 7 or 8
16:58:24
or whatever. So those are always going to reside 6 7 and 8 over here. But the
16:58:30
thing is I'm always get bringing stuff out from the out stack. So the order of
16:58:37
the way stuff has been entered and being taken out is always going to remain as
16:58:43
it is because now if I have to do pop operations so first I pop then I I'm
16:58:48
going to pop element number one out. Now notice that one was the first element that was entered. Then if I have to pop
16:58:55
the one is no longer here. So I would have popped five out. Then if I have to
16:59:00
pop once again five is no longer here. Then I would have uh kicked seven out.
16:59:05
And now notice that this stack becomes empty once again. And notice that 1 5
16:59:10
and 7 is the same sequence of elements that we originally entered stuff in our
16:59:15
in stack or in the similar sequence. So we basically followed the principles of Q or FIFO but using two stacks. Now once
16:59:24
again our stack became empty. So the moment our stack becomes empty all we need to do is just dump all the data. So
16:59:30
once again we are going to dump all the six 7 and 8. And once again the sequence would get reversed uh because we are no
16:59:37
longer worried about stuff. And now if we let's say have to do peep operation once again we are always going to do
16:59:42
peep operation from outseg as well. So outst is going to be used for pop and peep operation and instag is going to be
16:59:50
used for push operation. And if we follow this simple philosophy we can
16:59:55
actually achieve first in first out using the two stacks that basically operates on the leo principle. And for
17:00:02
is empty stuff it's very straightforward that if our if both the stacks are empty we can simply return that whether our
17:00:09
given stack is empty or not. So it's quite straightforward. So I'm not even putting any effort. Now let's talk about
17:00:15
different time and space complexity. Okay. So time complexity for uh the uh
17:00:20
first first operation that is push operation. So push operation is always going to be big of one because we are
17:00:26
simply dumping a value within an array. Now for the peak operation and also for
17:00:31
the pop operation in the general case it's going to be big of one because once we have already dump all the data in the
17:00:39
inside the outst it's very easy to take data out but the thing is occasionally
17:00:45
we will have to basically do the operation of dumping all of these data over here and worst case this can become
17:00:51
big of n so there is just no way getting around it because that's what we are using and for is empty it's also going
17:00:58
to be go of one because it's not going to take us lot of time to check whether the given stack is empty or not. So
17:01:04
overall this was the full explanation on how we can do it. The idea is to just maintain two stacks where one is always
17:01:11
going to be used to input stuff and one is always going to be used to output stuff and then we would be able to achieve this. Now let's see the coding
17:01:18
solution. So the coding solution is quite straightforward. We have our class myQ and we are going to be using couple
17:01:24
of uh DQs or double-ended Q's to implement our instack and outstack. Um
17:01:29
now let's notice and we will keep on going on each of the methods. So for the push method it's quite straightforward.
17:01:36
We are simply going to push inside our instack for same way for the pop method.
17:01:41
First we are going to check that whether we need to move from the pop or not. uh
17:01:47
and then we simply are going to pop it from our outst. Same way for the peak. Once again we are
17:01:53
going to be using the method move if needed. This is the helper method we we have created that basically helps move
17:02:00
all the elements from instack to our outstack. And then this is also going to
17:02:05
return that what has been the peak result from this um outstack array. And
17:02:10
for the last one we are simply going to check that whether the both the stacks are empty or not. So we check that
17:02:15
whether instack is empty and outstack is empty. If that is the case, we can simply return true or false. Now our
17:02:21
move if needed method is quite straightforward. We are going to check that if the given out stack is empty,
17:02:28
then while we have any elements present inside the in stack, we are going to dump all of them into our outst. And
17:02:35
then once again we are going to come back to the appropriate out stack that is going to do pop operation or peak
17:02:40
operation that we will have to follow. So let's try to run this code.
17:02:46
And seems like our solution is working as expected. Let's submit this code
17:02:52
and once again our code runs beautifully beats 100% of all the other solutions and that is because this also runs in
17:02:59
big of one time constant time complexity. So everyone is basically achieved this solution. So now the
17:03:06
solution is present in our GitHub repository and link is in the description. So feel free to check it out from there. Thank you.
17:03:24
So the lead code problem we are going to solve now is called implement stack using cues. Now this one is also a lead
17:03:30
code easy problem and pretty popular problem because we are using two fundamental data structures to basically
17:03:36
implement each other. So this is going to be interesting. Now we all know that stack has the property of leo last in
17:03:43
first out. So whichever was the last element would be the first candidate to get out and meanwhile Q's have the
17:03:49
property that is FIFO that is first in first out. Now we need to implement stack using two Q's. That's the only
17:03:56
thing we need to do. And then we are given that what are the different operations we need to support. So we
17:04:01
should be able to push an element in at the top of the stack. We should be able to pop an element. And when we pop the
17:04:07
element, it has to be from the top of the stop stack as well. Pop top only shows that what is the current element
17:04:14
but we are just not popping it out. And then uh empty method just defines that whether the given stack is empty or not.
17:04:20
Now notice that we are going to be using Q to basically implement that. And lucky for us we are given the option to
17:04:27
implement it using two Q's. So here I have provided two Q's and we these are
17:04:32
the operations we need to support. Now I'm not too much worried about empty operations. So let's just leave it on
17:04:38
the side for now. Important ones are push and pop. And top is going to be very similar to pop. The only difference
17:04:44
is we are not just popping the value out. Let's try to understand that how does push operation would work in a
17:04:50
typical stack. If we had stack like this we and let's say the entry we want to
17:04:55
push it three it would come over here then four it would come over here then five it would come over here. Now in
17:05:01
this case if we had just one cube uh basically we would have three, four and five sitting in this order. But if we
17:05:08
had to take this one out then we would have taken three out but meanwhile we should have taken five out. Now notice
17:05:14
that we are trying to implement this using a single-ended Q not a double-ended Q because if it was
17:05:20
double-ended q we could have just inserted from both the ends and it would have been easy for us and also exited
17:05:25
from both the ends but that is not the case. So let's see that how does our push operation works in such a manner
17:05:32
that the element we enter is always going to end up at the beginning of the
17:05:37
cube. Uh so for that we are going to do like something tricky. We are going to
17:05:42
have Q1 and Q2 and whenever a new element gets entered it always gets
17:05:48
entered into Q2 second Q and we are going to make sure that Q2 always remains empty for now and then then only
17:05:56
we are going to insert the element and once we add value to the Q2 then we are
17:06:01
going to dump everything that is uh in the Q1 and then dump it into Q2 and then
17:06:07
we are going to swap names. So let's try to understand why we are doing each of these three steps and let's see each
17:06:13
three each of the three steps in action. So first step is that let's say I have value the one that I'm trying to enter.
17:06:20
So one is going to come at in uh in the Q2. Now currently in the Q1 I don't have
17:06:26
anything. So I don't have to move anything to the Q2. And now last step was to swap names. So we are going to
17:06:34
swap names between Q1 and Q2. Now why are we swapping names? Because remember
17:06:39
we defined that Q2 always has to remain empty where we are going to enter stuff
17:06:45
in and then things can change but basically Q2 we are always trying to make it as an empty Q. Now let's say
17:06:52
that one more element two is going to come in. Now this two is also going to end up inside the Q2 in the rear of the
17:06:58
Q2 and next step is going to dump everything we had from Q1 to Q2. So now
17:07:04
we would have move also inserted value one over here. So this is going to become 2 and 1 and this current Q1 is
17:07:10
going to become empty. Now after this is done once again we need to have a Q2 that is always empty. So we are going to
17:07:17
replace the names. So this is now going to become our Q2 and this is now going to become our Q1. Now let's say there is
17:07:23
an element three that we are trying to enter. Once again three is going to enter over here. Then we are going to
17:07:29
dump both of this 2 and 1 sequentially from Q1 to Q2. So this is going to
17:07:34
become like 3 2 and 1. And then uh we are going to have the names being
17:07:40
replaced. So q1 is going to become q2 and this is going to become q1 and
17:07:48
this is going to become an empty cube. Now notice that what is the property we are maintaining in each of the cube. We
17:07:55
have inserted values 1 2 and three so far. Now if this was just a simple stack we would have entered values uh such as
17:08:02
1 2 and three. So three should have been the first candidate to get out then two and then one. Now if we have to start
17:08:09
popping values out basically we would always pop it from Q1 and we would be
17:08:15
able to maintain the property that it this is going to look a stack like data structure where the value is going to
17:08:21
come out as if it was coming out of a stack. So this is why we are basically doing for the push operation we are
17:08:28
doing that always enter into the Q2 then move everything from Q1 to Q2 and then
17:08:36
swap names. So this is basically the whole core idea about solving this
17:08:41
problem. Now some might say this looks like a trick, some might say this looks like something that you mugged up. If
17:08:47
you had just put it put down your pen and paper and try to do some permutations and combinations eventually
17:08:52
you would be able to get come to this same conclusion as well. It's not very complicated. Now let's try to understand
17:08:58
that how does pop operation work. So we are always going to be popping out from whatever the value is present from the
17:09:04
Q1 as if this was a normal Q and for the top operation as well we are just going
17:09:09
to see that what is the current value at the top of the given Q1 but we are just not going to remove it. And for the
17:09:15
empty function, now notice that Q2 is always going to remain empty. So we don't have to worry about it. For is
17:09:21
empty method, we are going to check that whether the Q1 is empty or not. If it is empty, we can return true. Otherwise, we
17:09:27
can return false. And this is the whole solution basically. Now let's try to understand time and space complexity for
17:09:33
each one of them. Now time complexity is going to be bigo of n for all the insert operations because we are flipping
17:09:40
things around and changing names and whatnot. But for uh in order for top and for pop method this is also going to be
17:09:47
bigo of one and for empty method this is also going to be bigo of one and uh for
17:09:53
the space complexity since we are already given two q's we are always maintaining one q to be empty so
17:09:58
basically we are utilizing n extra space but thing is since this is already given so I don't think we need to worry about
17:10:05
that um that much so now let's quickly see the coding solution for this problem so the coding solution is quite
17:10:11
straightforward we are defining Q1 and Q2. These are the two Q's we are going to be using and we are using link list
17:10:17
to implement them. Then we are going to simply uh implement our push method. So
17:10:22
for that step one is to add elements to the Q2. Then step two is moving
17:10:28
everything from Q1 to Q2. So while Q1 is not empty we are going to enter
17:10:33
everything into Q2. And then last thing is using a temporary Q we are going to
17:10:39
be swapping the names between Q1 and Q2. So now this is the main operation push
17:10:45
operation. So one that that has been taken care of by the three steps we defined and then for the pop we are
17:10:51
simply going to pull whatever the first element is present inside the Q1 and for the top we are just simply going to use
17:10:57
peak method inside the Q1 and for empty method we are going to check that whether this given Q is empty or not. So
17:11:04
let's try to run this code.
17:11:09
It seems like our solution is working as expected. Let's update this code
17:11:15
and our code runs fine. Beats 100% of all the other solutions which is pretty good. But since this is running in like
17:11:21
a constant time so that's why we are seeing this result. Once again the coding solution is present in our GitHub
17:11:26
repository. So feel free to check it out from there. Thank you.
17:11:44
So the lead code problem we are going to solve now is called design circular cube. Basically we need to implement a
17:11:50
FIFO like structure. Now we all know that what FIFO is. It is simply a cube where you enter stuff from one end and
17:11:57
then the stuff gets out from the other end. So whoever was the first in the queue would be the first to get out of
17:12:02
the que. Now this is going to be a similar structure but this is going to be a circular cube. So the last position
17:12:10
inside the cube is also going to circle back to the first position inside the
17:12:16
cube to make it a circle and we can also refer to it as a ring buffer. So let's try to understand that what is the
17:12:22
difference between a normal cube and a Q that is a circular cube. So this is
17:12:28
currently a normal cube. Now inside the normal cube we can have let's say uh this is going to be our front of the
17:12:34
queue and this is going to be the rear of the cube. So let's say that we we started entering stuff at the front of
17:12:40
the cube. So then we can have entries like 10 11 12 and 13. Now let's say for
17:12:45
some reason we get rid of this 10. So in this case because even though we get rid of this 10 currently this space is empty
17:12:53
we always enter stuff in the cube at the rear end. So basically we cannot enter
17:12:59
stuff over here unless we do the operation of moving all of these entries one by one and then only we can enter
17:13:05
stuff over here. So you can notice that how quickly this can become annoying and
17:13:11
we can have like basically insertion happening at either bigo of n space or
17:13:18
basically we just choose not to do if we are using an array based implementation. Now let's try to understand that what is
17:13:25
the concept of a circular cube. So we notice that we are going to have a cube
17:13:30
that is once again going to look like this. But the position of front and rear is going to keep on shifting from um
17:13:37
every time we enter and basically if we reach to the end basically the rear is going to switch back like this. So even
17:13:44
though it looks like a normal cube uh visually we can understand it to be more
17:13:50
of like a circle and we can have uh like a circle like this where we can
17:13:55
basically enter four values and let's see that how this is going to work in action. Let's say that currently our
17:14:00
front is also here and our rear also sits at the same position. Okay? And we are always going to enter stuff from the
17:14:08
at the rear place and we are going to eliminate stuff from the front place. So front we basically dq and at the rear we
17:14:17
basically nq. Okay let's try to just understand this for now. So we are going
17:14:22
to have our front and rear right now. And at the rear end we are going to enter stuff. So let's say that we want
17:14:27
to enter uh value number 10 once again. So we entered value number 10 and let's try to see that how does it look inside
17:14:34
the ring um or ring buffer as well. Okay. Now our front is going to remain
17:14:39
over here because this is where we can get stuff out. You get out of from the queue from the front of the cube. Okay.
17:14:45
Not from the rear of the queue but you enter through the rear of the queue. Now our rear is going to change and this is
17:14:51
going to be our new rear. So once again let's say that value we are going to enter is 11. So we can enter 11 over
17:14:57
here. And notice so far this is the front. Okay. So front is not changing but uh rear is changing. And once again
17:15:04
let's say if we have to enter value number 12 once again the rear uh is here. So because we entered 12 over here
17:15:10
and this is where rear is. And if we have to enter value number 13 once again
17:15:15
we would be able to enter value number 13 over here. Now this time rear sits over here. And same way for value number
17:15:22
13 the rear sits over here. Now notice that in this case because we
17:15:27
have front and rear constantly switching. Now if we have to encq any more elements we cannot do it. Why?
17:15:33
Because the whole que is full. So since this is already full we cannot enter stuff right now. So what is going to be
17:15:40
the next approach? Okay let's say that we get rid of some elements. So we do like dq and then dq again. So we get rid
17:15:46
of two elements and notice that we are always removing from the front. So we got rid of this 10. So now this is no
17:15:53
longer here and our front switches back to the next element. So now this becomes
17:15:58
our new front and same way if we get rid of 11 as well. Once again our front
17:16:04
switches again and then we can get rid of uh this element as well. Now notice
17:16:09
that if we have to enter stuff in basically we are going to check that whether the Q is full or not. Q is
17:16:14
currently not full. So we can just simply switch our rear to the next element and here we can enter value
17:16:21
number 14. and our 14 is going to live over here. Meanwhile, our if we have to
17:16:26
remove element, we can still remove 12 because we already have it covered through the ring buffer. And notice that
17:16:32
previously in the previous Q, we had to basically like jump the elements. We don't have to do that. We are simply
17:16:39
jumping the pointers and we are utilizing the same space to basically work as a circular cube. So this is the
17:16:46
whole concept. And let if we go back to the problem statement, let's see that what are what are they asking us for us
17:16:54
to solve. Basically we want to implement a my circular cube class. Now for this
17:16:59
class we will have to implement these methods. So first method is called front. Front means that it only gets
17:17:05
that what is the front element from the cube and if the cube is empty we return minus one. Rear means that we only get
17:17:12
the last element of the cube and if it is empty we return minus one. But basically we are just fetching that what
17:17:17
is the current value. We are not removing them from the cube. Next element is boolean and q and it has
17:17:25
value. So we are going to check that what is the value we have to insert. And if the insert is successful we return
17:17:32
true. If it is not successful we return false. Uh same way for dq. If it is successful we return true. If it is not
17:17:38
successful we do not return true. But dq means that we are kicking element out from the existing cube. And then we have
17:17:45
two methods is empty and is full. This is simply to check that whether the Q is empty or whether the Q is full or not.
17:17:51
So once again let's just repeat all of our operation. We all know that how does NQ and DQ is going to work. Same way
17:17:59
front and rear can also work. Basically we simply have to fetch that what is the current value at the front of the queue
17:18:05
and rear of the cube. And then we have the method of is empty and is full. So
17:18:10
how each of them is going to work? We'll just try to understand it visually very quickly. Essentially we are doing the
17:18:16
same operation. So currently once again we are going to have uh an array like this. Currently both front and rear sits
17:18:23
at the same place. And if uh we are being asked that what is the front and what is the rear. Currently the que is
17:18:28
empty. So we can simply return empty. Now in this case if we have to check that whether the Q is empty or not all
17:18:34
we can keep track of a counter called size and that is going to initialized as zero and then we can have a counter
17:18:42
called capacity and uh using this capacity it would basically be mean that
17:18:47
what is the current capacity or how many elements it can hold in the cube. So current capacity is going to be three.
17:18:52
Now every time we nq stuff we are going to do size plus every time we dq stuff we are going to do size minus minus. So
17:19:00
whenever we have to check that whether the given Q is empty, we simply check that whether if the size is equal to
17:19:05
zero then it is empty. If it is not zero then essentially it's not empty. And for
17:19:11
full we only have to check that if the size is is equal to three or whatever the capacity is. If size is equal to
17:19:18
capacity then it is full. If not then it's not full. So these two are very
17:19:23
easy to manage. We would be able to do it for front and rear. It's pretty much the same concept that we will have to
17:19:30
have two pointers that are going to keep on switching between uh the given array
17:19:35
to to figure out that where we need to enter the stuff. Now a better way to do it is using the size variable and I'll
17:19:42
show it to you in the code that how we are actually going to be doing that but for simplicity we are just understanding
17:19:49
that we will have two pointers front and rear that is going to be moving around the given cube. Now for NQ and DQ
17:19:56
essentially NQ we are entering some value as well and for DQ we are just saying that whatever the value that just
17:20:02
gets out we don't have to return the value we just have to say that whether it was true or false that whether it
17:20:08
kicked element out or not so let's say if NQ is 10 so we enter value 10 over here and then we because we enter at the
17:20:15
rear then our rear gets updated to the next value uh in case we will have to encq stuff so currently uh now if we
17:20:23
have 20 Once again it's over here. Our rear sits over here. Front sits over here. Once again if we have to enq new
17:20:29
entry we will have to check that whether the space is available. If it is available we enter to the next element
17:20:34
by updating the rear pointer and that's it. Now the Q is full because the and once again with everything we are
17:20:41
increasing the size because all we have done is the NQ operation. So currently the size is going to be three. And then
17:20:46
if we have to dq all we have to do is just update the front counter and then get rid of this element from the given
17:20:53
cube. And now our front sits over here. So once again by manipulating front and
17:20:58
rear pointers we would be able to do all of these operations. I think it's more of like a conceptual problem than an
17:21:05
actual implementation problem. So in my opinion this should have been easy problem. uh it's just the only
17:21:10
difference is we are playing around some pointers and uh if we have to see time and space complexity for each of the
17:21:16
operations it's going to happen in big of one time complexity because we are not doing anything special in terms of
17:21:22
space complexity it would be big of k where k is the total size of the cube that we will have to be allocated and
17:21:30
now let's quickly see the coding solution for this one now let's try to understand the code basically we have
17:21:35
our my circular q class and we are going to have four different variables. First one is the data that essentially the
17:21:43
sequence will have to enter the data in. Then we have the capacity of the given uh que and then we have the head
17:21:49
position. So this is going to be the starting pointer and then we have the total size of the cube. So instead of
17:21:55
just utilizing like front and rear both pointers we are only going to be utilizing the position of size. So total
17:22:01
size of the cube and what is the current head position or the first position within the cube. And now let's try to
17:22:08
understand that how our Q is going to operate. So essentially the constructor is going to return that what is the data
17:22:15
is current that is currently present that we have to enter and then what is the given capacity of the given cube. So
17:22:22
this is going to determine that how many elements we should be able to add and head and size are by default going to be
17:22:27
zero. So they are going to be starting at the first position. Now whenever we have the NQ method we are always going
17:22:34
to enter it at the rear end and whenever we have the dq method we are always going to remove it from the front of the
17:22:40
cube. So let's try to understand couple of helper methods first. First one is is empty and is full. So is empty method is
17:22:47
quite straightforward. If the given size is equal to zero, we return is empty. If the size is equal to capacity, we return
17:22:53
is full. Okay. Now whenever we are nqing stuff we will first check that whether
17:22:59
the given q is full or not. If it is full then we can't do anything. If it is not full then we are going to determine
17:23:06
an element called tail that is going to give us the idea on where we have to insert the element and that is defined
17:23:13
by head position plus size modulo by the current capacity. So this is going to be
17:23:18
our rear pointer where we are going to add stuff in and then we can simply insert that value and then update the
17:23:25
size of the Q. So when first let's repeat first we will check that whether the Q has enough size to enter the value
17:23:31
or not. Uh if it does then we are going to first of all find the rear pointer and then we are going to add over over
17:23:37
there and then simply return true. Same way for the dq stuff we are going to check that if the given q is empty then
17:23:44
we can simply return false because there are no elements to be dqed. If that is not the case we will first try to
17:23:50
identify that what is the position where we are going to be dqing stuff. So that is going to be head is equal to head + 1
17:23:57
modulo by cap and this is going to be our front pointer that we were discussing and then we can return we can
17:24:03
reduce the size of the existing cube. Now in terms of for the front and for the rear it's quite straightforward. We
17:24:10
simply return whatever the value is present at the head or at the tail of the given que and then uh we will again
17:24:16
be checking that whether the given q is empty or not. If it is empty we can't return anything. If it is not empty then
17:24:22
then only we will return. So this is a very simple implementation of all the six methods that we were discussing. Now
17:24:27
let's try to run this code. Okay. Seems like our solution is working
17:24:34
as expected. Let's submit this code and our code runs beautifully uh beats
17:24:42
all the other solutions because it's more or less bigo of one or constant space time complexity. So once again the
17:24:49
coding solution is present in our GitHub repository. Feel free to go and check it out from there. Thank you.
17:25:07
In this problem, we would be able to learn concepts such as Q, dynamic programming, breath for search, bunch of
17:25:14
different graph concepts and also how you can actually approach solving a problem from a very different
17:25:20
perspective. So without any delay, let's get started. So the lead code problem we are going to solve now is called open
17:25:26
the lock. And we can see that this one is a lead code medium problem. But we can also categorize this as a hard
17:25:31
problem in some facets. So let's understand that what does the problem statement is asking us to do. We are
17:25:38
given a log that is in front of us that contains four circular wheels. Now we all have seen the log where you can
17:25:45
rotate it from 0 to 9 and we are currently given a log that contains like four such wheels that we can control in
17:25:51
different manner. Now we are given the starting position that is going to be 0 0 0 0 0 and we are also given a target
17:25:59
value that represents the value of the wheel that we will need to reach in order to unlock the wheel. So that's
17:26:06
pretty much uh quite straightforward. Now the thing is we are also given a list of dead ends which means we must
17:26:13
avoid these dead ends and uh no matter how we try to rotate around the wheels
17:26:19
we must always make sure that we never reach to a point where we are at a dead
17:26:25
end. So we will have to circle back around it or find some other way. Uh and we once we do that once we reach to a
17:26:32
target value we need to return the minimum number of total number of turns
17:26:37
that are required for us to make in order to reach to that value. If we can't reach we will need to return minus
17:26:43
one. Now the complicated part in this problem is actually understanding the whole problem. Now we are given an
17:26:50
example of 0000 0 which means four circular lock but that makes things much
17:26:55
more complicated. What approach I will do is we will try to understand this problem on what if we only had just one
17:27:02
lock. What if we had two locks or or like two circle locks and what if we had
17:27:08
three circle locks and then we will try to see that how we can form solution for a complex problem like this. So let's
17:27:15
try to understand the problem. Let's say that we are currently given a target of seven and we are given the initial
17:27:21
starting position as zero. Now currently I'm not talking about dead ends but I'll get back to it in just a second. So
17:27:28
let's try to understand that from this zero how can we reach to this seven. Um well first of all from this zero we have
17:27:35
two options. We can either go from 0 to 1 or we can go from 0 to 9. Okay. Now
17:27:42
once again from this one we once again have two options. From one we can go back to two or we can go back to zero.
17:27:48
But the thing is zero we have already come from zero. So we are not going to go back to zero. Let's just say keep it
17:27:54
for simplicity. From nine we have one once again two options. We can either go back to eight or we can go back to zero.
17:28:00
Once again we are not going to do that. From two we have once again two options. We can either go to three or one. Uh and
17:28:07
from 8 we have two options. We can either go to seven or we can go back to 9. So now we have reached to seven. And
17:28:14
this is the solution that we are basically trying to achieve the target value. So how many turns did it took us
17:28:20
from reach to zero to seven? Well, this was the first turn. This was the second
17:28:25
turn and this was the third turn. So three is the minimum number of turns required for us to reach to the value
17:28:32
seven. Now let's presume that in this case if we had a dead end located at
17:28:37
position number eight. What would have happened in that case? Well, once again we would have proceeded in the same
17:28:43
manner right now. But at the nine the moment we saw that one option is zero which you have already seen and another
17:28:50
option is 8 which is a dead end. So we cannot move forward with eight. So in that case this entire path closes for
17:28:58
us. So we no longer would be able to consider this one. So the only way for us to move forward would be using this
17:29:04
path where eventually we would have reached to value number seven and that would have taken us basically seven
17:29:11
different ways in order to reach that and in this case seven would be the minimum number of clicks we would have
17:29:16
to make in order to reach to the final position. So that is the answer we will have to return. So now what are the
17:29:23
things we are ignoring when we are building the solution? Number A, we are always checking that whether the
17:29:28
solution we are reaching to or the data point we are reaching to whether it is part of the dead end or not. If it is
17:29:35
part of the dead end, we are simply stopping exploring any further from that point or point onwards. That's number
17:29:42
one thing we are doing. Second thing is uh we are also checking that all the things that we have already seen are we
17:29:48
also uh repeating those or not and we are not repeating those. So somehow we
17:29:54
will have to find a way to keep track of that what are the different dead ends that we should never go and what are all
17:30:00
the elements that we have already seen that we should never go. These are the two intuitions we can build. Now let's
17:30:06
try to explore a two lock system where we are starting from 0 0 and let's say for simplicity our target value is 19.
17:30:12
So what we are going to do is that we have four different possibilities at this position. First position is going
17:30:18
to be 0 1. Next position is going to be 1 0. Next position is going to be 09 and next position is going to be 9 0. So
17:30:25
notice that for each character we are taking two possibilities on whether this value 0 can be the subsequent value 1 or
17:30:33
the previous value 9 while we are keeping the other value unchanged and then we are repeating the same process.
17:30:39
So logically even at the 01 location once again we are going to have four possibilities. First possibility is that
17:30:45
the 0ero remains remains as it is. So in that case this one can become two so we
17:30:51
can become 02 or we can this one can also become 9. So we can become 09. Now
17:30:56
notice that 09 is already here but we are also once again can we can compute beforehand. So eventually when we get to
17:31:03
this point we might have already computed that but let's not worry about that at the moment. So these are the two
17:31:08
possibilities. What are the next two possibilities? So next possibility is that this zero can be turned into one.
17:31:15
So it can either become 1 one or it can also become 9 1. Okay. Now let's try to
17:31:22
calculate more possibilities. But for simplicity we are just going to consider this 09 because that is going to give us
17:31:28
the answer. So the 09 can be can have one of the possibilities as 1 9 if we
17:31:34
just convert this 0 into 9. So this is the target that we are trying to find.
17:31:39
Now notice that how many clicks it took us. It took us 1 2 and then three. So answer is going to be that it took us
17:31:46
three attempts to come up with this answer. Now logically what we are doing
17:31:52
to build this solution. Well basically we are just building a decision tree for
17:31:58
any given set of nodes. So what we are doing is we are currently given a
17:32:03
starting point. So we can treat the starting point as one of the node within the graph that is going to be the entry
17:32:10
point in the graph and then we are going to have a connected graph where we for
17:32:16
each of the different possibilities they are going to be the nodes in the graph and each of the different connections we
17:32:22
can make would be the edges within the graph. Now once we find that from point
17:32:28
A all the way up to point B we can reach in any particular fashion then this is
17:32:34
going to be let's say the answer that we are trying to get to. So all the different edges is going to be sum of
17:32:40
all the different edges is what we are looking for. So these are the number of clicks required for us to come to that
17:32:46
solution. That's a given fact right now. How do we get there? Basically what we
17:32:51
are doing is that at initial position we have multiple different possibilities
17:32:57
for each of the this possibility we are exploring all the other possible options. Same thing we are doing for the
17:33:03
previously calculated value. Same thing we are doing for the previously calculated value and so on and so forth.
17:33:09
So logically what we are doing is we are traversing in the level order or in the
17:33:16
breadth of the given uh problem. So we are doing like what do we call as BFS or
17:33:21
breath first search traversal where from one point we are exploring all of its
17:33:26
neighbors and then for each of the neighbors once again we are exploring all of its neighbors and some neighbors
17:33:32
can be interconnected that's where we are seeing an example where this 0 has a
17:33:37
neighbor that is 09 which is also a neighbor of this 01 because once again it is connected so logically we can say
17:33:44
that this is connected to this point so that that's why this is this looks like a tree but it is actually a graph
17:33:50
because there are circles or there are cycles that can be formed and tree does not have any cycles but let's not get
17:33:56
into the different concepts. Let's just stay focused towards our actual problem we are trying to solve. Now we know that
17:34:03
we are trying to compute a breath first search. Now breath first search is achieved using cues. So whenever you are
17:34:11
trying to solve any particular problem and you reach to a conclusion that we are reaching a breath for search
17:34:17
approach we will have to use a cube. How does breath first search approach works? Let me give you a very simple example.
17:34:23
Let's say that currently I have one possibility A. Now for this A we are going to have three different uh
17:34:29
neighbors that is going to be B, C and once again D. And let's say that for
17:34:34
this B once again I'm going to have all the many different like X Y and Z. These
17:34:40
are going to be its neighbors. So what what I'm going to do is we know the concept of Q. It operates on first in
17:34:46
first out principle. So we are going to insert A at the beginning of the cube.
17:34:52
So currently my Q is going to be empty. I'm going to add a value entry a over here. And then I'm going to enter all
17:35:01
the neighbors of A that are currently present. So these are the values going to be B, C and D. And once I have
17:35:08
explored all the neighbors of A, then I can get rid of A because I have already processed A. But in the meantime, I
17:35:14
haven't processed all the remaining values because they are still within the que. So we will keep the Q going until
17:35:21
we reach to a point where the Q is completely empty. and Q would only be empty if we have taken taken into the
17:35:29
consideration of all the different neighbors that exist. So now for B I have entered the value X, Y and Z in the
17:35:34
uh loop and after entering that I can get rid of B because I have already explored this solution and then all I
17:35:41
need to do is just see all the neighbors of C. C does not have any children. D does not have any children. X, Y, and Z
17:35:48
is what I was looking for. And let's say that Z is the answer that I'm looking forward to. I have already processed Z
17:35:53
because through Q or through BFS and then whatever the distance was from A to
17:35:59
B to Z I can keep a track of in some sort of let's say steps variable or
17:36:05
answer variable that is going to be storing all the results. So this is the whole solution that we are trying to
17:36:10
build that now I gave you an example of one string and two string. Same can be
17:36:16
true if we are given three different locks. Once again we are going to have multiple different permutations and
17:36:21
combinations that we can make and then we would be able to just driving that solution forward. Now we know that we
17:36:28
need to avoid dead ends and we need to avoid all the values that we have already seen. So what we would do is we
17:36:34
would just create a hash set for both of these things. And after because why are
17:36:40
we creating hashetss? because uh even though it's going to consume extra space, we will have a separate data
17:36:46
structure that performs all of the search steps in big of one. So we are going to be storing the results that any
17:36:53
pair that that is part of dead end. If that is the case, we will just stop immediately and we would pop that
17:36:58
element from the queue. So we would not be exploring any of the neighbors of that particular element. If we see that
17:37:05
that element is already we have seen something. So we know for a fact that it does not lead to a proper conclusion or
17:37:11
its neighbors are already part of the queue. So we don't even need to consider that for our solution. And that would be
17:37:18
able to give us eventually that we would reach to a node that is our target node
17:37:24
based on just different probabilities or different permutations and combinations of solutions. Now what is going to be
17:37:30
the time complexity in this problem? So time complexity for this problem is actually going to be constant time
17:37:37
complexity. Why? Because we are for sure given that there are only going to be
17:37:42
four different possibilities. So since there are only four different possibilities within a lock, the maximum
17:37:48
number of combinations we can have is going to be zero all the way up to 9999.
17:37:53
So in total 10,000 combinations and for each of the pair or each position we can
17:38:00
have eight possibilities. So it's 10,000 multiplied by 8. So overall we have we
17:38:05
since we only have 80,000 possibilities that is the maximum time worst case time
17:38:11
complexity we can have. So because this is a finite number I'm considering this as a constant time complexity. But I
17:38:17
know your interviewer is not going to ask you a number like this. What if this number pair was going to be in millions?
17:38:24
So in that case the time complexity would have been to go over all the different possibilities of nodes and
17:38:31
edges within the given graph and that would have been big of multiplied by n
17:38:36
where m is the total number of nodes and n is the total number of possibility for each of the nodes or total number of
17:38:42
edges. So overall your interviewer would be would be very pleased with this
17:38:47
explanation of time complexity for the space complexity because we are using an additional hash set to store the values
17:38:55
of all the already previously calculated result it's going to be big go of k where k is the total number of um
17:39:01
possible combinations we can add to dead ends and our hash set. So whichever is larger would be the would be our space
17:39:08
complexity. So I hope this solution makes sense. The core concept of this
17:39:13
problem was to explain you that how does a BFS work and how you can break a
17:39:19
complex problem down into bunch of different smaller subsets and then try to make your way around through building
17:39:26
logic through that way. And now let's move on to the coding for this.
17:39:31
So here is the coding solution. First of all, we are going to define a hash set that is going to take care of all the
17:39:37
different dead ends that we are provided. And then we are going to check that if the dead end contains the 0 0 0
17:39:43
basically the very first node we can simply return minus one. And also we can check that if the 0 0 0 is the target
17:39:52
that we are given that is one of the edge cases we can simply return zero because we don't have to change any
17:39:58
locks. Now let's see our breath for search implementation. So we are going to have a cube where we will add bunch
17:40:04
of things. We are going to have a hash set that where we are going to keep track of all the elements that we have
17:40:10
already seen. And then we are going to start our queue with adding the value of
17:40:17
uh 0000 0 as the first node in the cube. And we are also going to be marking it eligible for our scene uh hash set. So
17:40:25
in future we don't just repeat the element. Now initially we are at step zero. So because we haven't made any
17:40:33
clicks. Now our breath for search implementation starts that until Q is
17:40:38
not empty we are going to check that what is the current size of the cube. Then we are going to check that for any
17:40:45
single element that is currently present within the given cube. We are going to pull or get rid of that current item.
17:40:53
Then we are going to check that whether that is present inside our one of our uh
17:40:58
dead end. If that is the case we will just get rid of it. we will just skip those states because we don't need to
17:41:04
worry. We don't need to enter any of its subsequent neighbors. Um if that is not
17:41:09
not the case, if it is the target, then we can simply return the steps as well. If that is not the case, then we will
17:41:16
have to generate all the neighbors by turning the wheel plus or minus one. And
17:41:21
for each of those neighbors, this is the simple logic on how we are going to be doing that. For each of those neighbors,
17:41:28
we are once again going to adding them up to the cube and we are also going to
17:41:33
check that whether they are part of the given u dead end or the scene element
17:41:39
that we have seen. If that is the case, we would not be adding it into the cube. If not, we would be adding it into the
17:41:45
cube. And uh that goes for both turning it up and turning it down. Both the different possibilities. And we will
17:41:51
keep on repeating this. And with every new neighbor or new level being added,
17:41:56
we will update our steps. So total step it takes to reach to that next uh
17:42:02
possibility or set of levels. And if if uh we have a combination, we should be
17:42:08
able to reach it within this cube. If we don't, then we simply return minus one. So this is the full coding solution.
17:42:14
Let's try to run our solution.
17:42:19
Okay, seems like our solution is working as expected. Let's submit this code
17:42:28
and our code runs beautifully beating almost 60% of all the other solutions which is pretty good. We are also really
17:42:35
efficient in terms of memory usage. So that is also nice. Now once again the coding solution is present in my GitHub
17:42:41
repository. So feel free to go and check it out from there. Thank you.
17:42:58
The lead core problem we are going to solve now is called Dota to Senate. This one is a medium problem and also in this
17:43:04
problem we are going to play a game between two political parties. First one is called radiant and second one is
17:43:10
called dire. But for simplicity throughout this video we are simply going to refer to them as Republicans
17:43:15
and Democrats. If you want you can read through this whole statement or let me quickly explain you the rules. So the
17:43:21
problem statement is we are currently given bunch of different senators that are present in a simple cube and each of
17:43:28
them is going to be doing a vote. Now in this vote each senator belongs to a
17:43:34
different party. So we have some senators that are currently representing Democratic party and then there can be
17:43:39
some other mix of bunch of different Republican parties but overall it's going to be either Democrat or
17:43:45
Republican in whatever sequence. Now the thing is we need to determine that which
17:43:50
party is going to win. Now how would a party win? Basically any single senator
17:43:57
who comes in to vote that senator currently has two abilities. number one ability is that that senator would be
17:44:04
able to kill someone's vote or get rid of some senator from the other party. So
17:44:10
let's say that if this guy is a Republican then this person can kill or get rid of a Democrat vote. So that
17:44:17
Democrat would not be able to vote and vice versa is also true. And second thing this senator can do is that if
17:44:24
there does not exist any other person that they can eliminate then this person would should be able to declare victory.
17:44:31
So let's try to understand that how this is going to work and also the voting is
17:44:36
going to keep on continue until there are uh existing senators present. So if
17:44:42
one senator has done the voting and if that senator survives that senator
17:44:47
basically moves to the back of the queue and then voting would continue. So let's try to understand this with an example.
17:44:54
Suppose we are currently given a sequence like this. This is a very small sequence. So what is going to happen?
17:45:00
The first person currently in the list is a Republican uh person. So this Republican senator knows that there are
17:45:07
more people currently present inside the given queue. That Republican senator
17:45:12
also knows that they need to eliminate one Democrat and that is that should be
17:45:17
like the immediate first Democrat that they can find. Okay? So the first Democrat that they can find is going to
17:45:23
be placed over here. So they are going to get rid of this Democrat and what is going to happen is that then this
17:45:29
Republican casted their vote and they cannot declare their victory because there are still more Democrats. So they
17:45:35
are going to go to the back of the queue. So this is the initial position RD. Then after round one basically we
17:45:43
are we would have this guy eliminated. So we would have a Democrat and a
17:45:49
Republican because this Republican goes back and this Democrat comes to the front and after round one now once again
17:45:56
it's Democrat's turn. So once again they can they know that there exist a Republican so they will get rid of this
17:46:02
Republican and then join the queue again. So in the round two we would only have one Democrat left and at this
17:46:09
moment we should be able to see that because it's only one Democrat there is no one else to eliminate. then this guy
17:46:15
is going to declare victory and this is what we need to return. Now let's try to take one more slightly longer example.
17:46:21
Okay. So let's say that we currently have uh three Republicans then uh four
17:46:27
Democrats and then let's say we have one more Republican. Okay. So in this case what is going to happen now? Logically
17:46:34
it seems that the voting is divided fair and square. But let's see that how would things change with each different turn.
17:46:42
So first turn is this Republican guy's turn. So he knows that this is a Republican, this is a Republican. He he
17:46:48
won't do anything. But this guy would get eliminated and then he would go back to the queue. So now we would have two
17:46:54
Republicans, then three remaining Democrats and then once again two different Republicans. After that we
17:47:01
will have one more Republican that would be able to kill or eliminate one more Republican. So basically we would have
17:47:07
one Republican and then two Democrats and then once again uh three different
17:47:12
Republicans over here because this guy would go back once again this Republican would get rid of this Democrat. So and
17:47:20
then they they would jump to the back. So next round we would have one Democrat and then we would have four different
17:47:26
Republicans. After this one this Democrat would get rid of one Republican. So now the we would have
17:47:33
this Democrat would go back and then we would have these three Republicans and then one Democrat and now this guy is
17:47:41
going to get rid of this Republican. Oh sorry this Democrat and in the end we are going to be left with three
17:47:47
Republicans and so they are going to be declaring the victory. So this is the
17:47:52
whole um solution or the whole problem statement. Now let's try to understand
17:47:57
that how would we solve them. So at a very basic level if we are only given
17:48:03
let's say a simple scenario where we are given bunch of different possibilities what is going to be the brute force
17:48:09
approach that we can take well it's quite straightforward number one thing we are going to do is for each
17:48:15
republican or each r we would have to keep on going into the remainder of
17:48:20
entire cube until we find a d. If we find a D, we will basically eliminate
17:48:27
this D or somehow find a way that this D should not be counted based off of its index value and then we would put this
17:48:34
guy back. So then we would have a shorter um string in the next round. So
17:48:39
once again, now we are going to have R R and then D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D and once again this R because
17:48:44
this R goes back and once again we are going to repeat the process. Now what is going to be the complication part for
17:48:51
each of the element? We would be scanning all the remaining elements and we would be continuing doing that for
17:48:57
all the different elements that are present. Now slowly we are reducing the size of our Q but overall it's still N
17:49:03
multiplied by N work we are doing. So this is going to be the worst case scenario that this is how we would be
17:49:09
able to solve this problem. Now let's see that is there a way we can make things faster uh in this existing
17:49:15
scenario. Well, if this was a straightforward voting uh where we could
17:49:21
just uh majority only wins, then we could have simplified in just one simple iteration. We would just go over this
17:49:28
entire uh exercise and then try to find a place whichever has the higher number
17:49:33
of votes basically declares the wins. But this is not the case here where if we let's let's take an example like this
17:49:40
that in this case we only have two Democrats and three Republicans. What's going to happen? this Democrat is going
17:49:45
to eliminate this guy's vote and then would go back. So we would have D and then R R and then once again D. Then
17:49:52
once again this Democrat is going to eliminate this guy's vote. So once again we are going to R D and D. So now this
17:49:58
Republican can eliminate this guy's vote. But once again we would have D and R and then this Democrat would be
17:50:03
replacing this Republican's vote. So notice that even though we only had two votes over here out of three votes,
17:50:10
still these guys win because of just sheer positioning. So a simple fall
17:50:15
through would not work. What would be the approach or optimal way we can solve this problem? Well, we can solve this
17:50:22
problem using two cues in this case. Now, how would we use two cues? Let me give you the whole solution. We'll try
17:50:29
to walk through it. Let's take the example. Let's say that we currently have uh this kind of scenario and let's
17:50:35
see that who is going to win. Okay. Now we know that this uh what is their current positions in terms of location.
17:50:44
Uh we can mark them out. So let's just mark the index values that where they are currently located
17:50:50
and at the same time we are also going to keep track of them in two different cues and each Q is going to re uh
17:50:57
represent one party. So we would have one Q that is simply going to represent uh the uh Republican party and then we
17:51:05
are going to have another Q that is simply going to represent the Democratic party and for each of them we are we
17:51:12
will have the pos positions of the Q located and based on that we would decide that whether one should stay
17:51:19
inside the queue and come back or should they be eliminated. Now we know that Q
17:51:24
follows the principles of FIFO first in first out and we are also going to be utilizing that in quite heavily. So
17:51:31
let's start creating our cues. So and we would be entering just the index positions in the queue. Okay. So
17:51:38
currently we have Democrat and Democrat sitting at position 0 and 1. So 0 1. And then this Democrat is sitting at
17:51:44
position number four. So let's just put it over here. And then we have 2 3 and five. So let's just put put it over
17:51:49
here. Now let's see that how our Q is going to work. First of all, we are going to be fetching both of these
17:51:56
entries and we would only pick the small smaller entry. So we know that amongst two and zero, zero is the smaller which
17:52:03
means two would be eliminated. So we would simply get rid of two. So two
17:52:08
would not be present anymore. But now with with this zero, this zero is going to the back of the que. And what is
17:52:15
going to be the back of the Q loop position? basically with every single size the uh the size of the Q shrinks by
17:52:23
one. So that's what we are going to put. So in this case after this elimination because we get rid of this republican
17:52:29
guy. Now the position of this Q is Q Q becomes uh instead of six we would have
17:52:35
five elements and this D is going to go to the very last element. So that
17:52:41
element number is going to be uh four like index value is go four and the position is going to be five. So we
17:52:48
would have four coming to the back of the cube. Okay. And at the same time
17:52:53
this zero would be eliminated from the existing cube. Now the same operation would get repeated amongst these two
17:53:00
values. So amongst three and one once again one is smaller and three is larger. And notice that we are also
17:53:06
keeping track of the current size of the que. So this time the size is going to four. The next time size is going to be
17:53:12
three. So the whoever gets added would be the this entry would be added in our
17:53:18
que. So now amongst three and one because this three is larger we can get rid of three because we don't care about
17:53:23
it. And now this one is going to come back to the que by becoming uh the value
17:53:30
number three. So let's rearrange these values four and three. And then this guy
17:53:35
is still five. That that is what uh the position is. Okay. Now since we
17:53:41
eliminated both of these guys. So notice that in the original cube we we these
17:53:47
two guys eliminated these two guys. So now we only have this D remaining and
17:53:52
they are trying to eliminate this R. And once again this guy is going to eliminate. So compared comparing four to
17:53:58
five. Once again this is going to eliminate um value number five. So now
17:54:04
this entire republican que is completely empty and this uh the size of our que is
17:54:10
going to become three once again. So index position is going to be two. So this guy would get eliminated and it
17:54:15
would come back to the queue as value number two. But now we don't have anything to compare against in the second queue. So we can simply declare
17:54:22
uh this democrat as v victor and this is the whole solution basically. Now I hope
17:54:29
that the logic made sense to you that how we were able to solve this problem.
17:54:35
Let's try to talk about time complexity in this case. The time complexity is going to be big of n because we are
17:54:40
simply iterating over this given q um once and then we should be able to basically come up with the solution very
17:54:47
quickly. So more or less it's not going to be like n² it's definitely going to be smaller than that. In terms of space
17:54:54
complexity, this is also going to be big of n or big of because we are using two
17:54:59
q's that is going to be the size of all the number n present probably. So once
17:55:05
again this is the whole solution and I hope it makes sense. Now let's see the coding approach for this one. And by the
17:55:11
way in this case uh throughout this pro program I referred to them as republican and democrat. There is no political
17:55:18
implication. I'm just trying to explain it in simpler terms instead of using terms like radiant and dire. Uh so yeah
17:55:26
that this is what the problem was. So let's see the coding solution now. So the coding solution is quite
17:55:31
straightforward. We are first of all going to define that what is the current length of our given uh senate string and
17:55:38
then we are going to initialize two cues one named R and the other one named D.
17:55:43
For both the cues we are going to iterate over the given string and then we are going to keep putting the value
17:55:49
in either um RQ or the DQ that we have created. Now we are going to simulate uh
17:55:56
different rounds and our basic condition is quite straightforward that until one of the Q is not empty just keep on
17:56:04
pulling both the numbers from both the Q's and for each of the position check that which Q is currently present that
17:56:12
has uh the proper value or that can eliminate the other other uh value and
17:56:18
then either get rid of the rem that value and the remaining value would go
17:56:24
back to the existing Q and we would keep repeating this process. Now in the end we are simply going to check that
17:56:30
whichever the Q is empty is not empty basically we are going to declare that as the vector. So let's try to run this
17:56:37
code. Okay, seems like our solution is working as expected. Let's submit this code
17:56:45
and our code runs beautifully beating almost 73% of all the solutions. It's also pretty good in terms of space
17:56:51
complexity and uh the solution is present in our GitHub repository. So feel free to go and check it out from
17:56:57
there. Thank you.
17:57:15
Hello friends, hope you're having a fantastic day today. So in this course we are going to learn everything there
17:57:20
is to know about heap and priority cube. We will understand that what is heap, what is min heap and max heap, what is
17:57:27
priority cube, how to implement heap, what are the benefits and limitations, time and space complexity operations you
17:57:34
can perform and the most important part under what type of scenarios should you consider using heap or priority queue to
17:57:41
solve the problem that is currently at hand. And my expectation is that by the end of this course, you should become a
17:57:48
complete pro in all sorts of heap and priority Q questions. So now without any delay, let's get started with the
17:57:54
course. So heap is nothing but a very special
17:58:01
type of binary tree. The thing is he heap contains two very special properties that differs it compared to
17:58:08
rest of the other binary trees and also it is slightly different than binary search tree as well. So let's understand
17:58:14
that what are the two unique properties or characteristics that heap persist. Number one characteristic is that heap
17:58:21
can be of two types. It can be either a min heap or a max heap. And for both the
17:58:27
property is very similar. The only difference is if the heap type is a min heap that means it contains a very
17:58:35
special relationship between a parent and its children child node. The relationship is that the parent node is
17:58:41
always going to be less than the child node. That's it. There is no particular packing order that left child is needs
17:58:48
to be smaller than the right child or what what not. Same way for the max heap. It's the reverse order that at any
17:58:54
given moment the parent is always going to be greater than the child and once that property is followed we can
17:59:01
conclude that uh this is a max heap. Let's say that suppose we are currently given these nodes that follow the
17:59:08
property of min heap. So logically the root node always has to be smaller than
17:59:15
its subsequent child node. If this is the case, we can clearly see that in
17:59:20
this case it follows the property of a min heap where at root level the value
17:59:26
is always going to be smaller than all of its subsequent child. So over here we
17:59:31
can see that this zero is the smallest element and if we see the child it is the value two and value three. Once
17:59:38
again even at the subree level we can see that this two is actually smaller than its child 6 and 7. Same way this
17:59:45
three is actually smaller than four and five. Now at a first glance this looks very similar to a binary search tree
17:59:52
where in the binary search tree we have a condition that left node or left child is always going to be smaller than or
17:59:58
equal to the right uh root node and that is always going to be smaller than the right child. So in this case though it
18:00:05
looks very similar this property is not always maintained in the heap and that's where binary search tree and heap differ
18:00:13
with each other where we can see that in this case we have value number four present over here as part of the right
18:00:20
child which in theory if this was to be a binary search tree four has to be
18:00:26
located somewhere over here because the six and seven are actually greater than four which means we do have some
18:00:32
property inside the left sub tree that is actually greater than some property in the right sub tree and this
18:00:38
disqualifies this particular entire tree from being a binary search tree. But
18:00:44
even though this is not a binary search tree, this is still a heap. So now let's
18:00:50
go back to our discussion. I mentioned that heap needs to follow two special properties. But I have only explained
18:00:56
just one property and uh that is that currently I have only explained you the property of the difference between
18:01:02
parent and child. The second property that heap contains is that heap tend to
18:01:07
be a balanced heap or a balance tree. Now what does a balanced tree means is
18:01:13
that at every single layer it tries to balance out the nodes and the only place
18:01:20
where heap may not be balanced is in the last layer. So let's say that in this
18:01:25
particular heap if we have to consider this this would still be a valid heap
18:01:30
because all the values are placed in proper balancing order and in the leaf
18:01:35
node or in the very last node we have all the values that have been filled from left to right and if this is the
18:01:42
case we can identify this as a proper heap. Now let's try to play around with some examples with these two properties
18:01:48
and we will try to guess that whether they are heap or not. Okay. So let's try to take this first example and we will
18:01:54
try to understand that whether this is heap or not. So as we can see in this case we are actually following the
18:02:00
property of a max heap. Why this one is a max heap? Because notice that at every single root layer the parent is always
18:02:08
going to be greater than its subsequent child values. So this is the property of a max heap. So at this layer max heap
18:02:15
property is followed. At this layer once again max heap property is followed. And once again so we can see that each of
18:02:21
the sub tree follows one property of the maxi which means this is correct. Next thing we will have to check that whether
18:02:26
this is a balanced tree or not. So currently we can see that this particular root node three contains two
18:02:32
child but that is because we only have the these many elements. So this is the only possibility. So this is still a
18:02:39
valid heap and this one is actually a max heap that is currently valid. Now let's try to take another example for
18:02:46
this one. Now this one seems like a min heap. The thing is this one is smallest
18:02:51
value and we can see that its subsequent children are greater than smallest value. So so far this is correct in
18:02:57
terms of min heap. If we see the structure of this particular binary tree, this also looks balanced binary
18:03:04
tree. So there is no issue with this. But when we do and identify the differences amongst these two elements.
18:03:10
We can see that if this was supposed to be a min heap then this value this child
18:03:17
this parent has to be smaller than its subsequent child which is not the case over here. So we can say that this is
18:03:23
not an not a proper example of a heap. So this is not a valid heap. Same way if you look at this example once again this
18:03:30
looks like a max heap. We can see that it is following all the property of child being smaller than its parents
18:03:37
appropriately. No issues with this one. But this is also not a valid tree because and remember I told you that all
18:03:44
the child has to be filled from left to right. In this case we had one space
18:03:50
over here and we have one space over here that has not been filled as as part of the child and we have this uh child
18:03:56
being located over here which means this is not a balance tree. So this is also not a valid heap and once again this is
18:04:02
one another example. So in this case we can see that once again property of max heap is being followed. But the issue is
18:04:09
that this is also not a balanced tree because of this particular element. If this was something like this, then this
18:04:15
would have been a valid binary tree but or a valid heap. But that is not the case.
18:04:23
The answer is quite simple. I mentioned that heap has two types. First one is a min heap and second one is a max heap.
18:04:30
And both allow us to gain a very specific property. With the min heap we
18:04:36
we can also always find the smallest element inside the entire binary tree at
18:04:41
the root location because remember what is the definition of min heap? It's quite straightforward that every single
18:04:47
parent has to be smaller than it all of its child. So in this case because this
18:04:52
is the parents or this is like the root tree or so it is parent to every single child which means this has to be the
18:04:59
smallest element inside the entire binary tree. So this is the most beneficial item for a min heap. Same way
18:05:06
with the max heap, we repeat the same uh thing in the reverse that parent has to be greater than all of its subsequent
18:05:13
child. And if this property is being followed, then no matter if we had like 500 elements inside our heap at every
18:05:20
given location, we would have maintained the property of it being a min heap or max heap. And we will we can always find
18:05:28
the root node to be the maximum element amongst all of these elements. in this case. So this is the primary benefit of
18:05:34
maintaining a heap that at any given moment we can identify that what is the
18:05:40
smallest element or what is the largest element inside the entire heap. Now question comes binary search tree does
18:05:47
the same thing. There is a slight difference and that slight difference is that I mentioned that in the binary
18:05:52
search we are maintaining the property of left child being less than or equal to root node and root node being less
18:05:58
than or equal to right child which is not what we are maintaining inside the heap. In the heap we only care about is
18:06:05
that at any given moment the relationship has to be between parent and child. And there is another reason
18:06:12
that why are we maintaining this type of hierarchical structure because or why
18:06:17
are we maintaining this type of balanced binary tree structure because we don't want to be in a situation where we have
18:06:23
all the nodes just like this or something very inefficient something like this this type of structure because
18:06:30
this takes lot of time to find and figure out elements that what are the smallest or what are the largest. If we
18:06:35
had a B balance tree basically we will have to do less number of iterations to
18:06:41
go down below inside our heap and that is another one of the benefit of heap compared to binary search and the reason
18:06:48
I'm putting so much emphasis on giving you the the differences between binary search tree and heap and other binary
18:06:54
trees is because this is the core concept that why are we actually building heap understanding this would
18:07:01
always give you a click in your brain whenever you encounter a heap related related question or whenever you
18:07:06
encounter a real life scenario where you have to keep track of the person or the a number of uh instances where you need
18:07:13
to find out the smallest value quickly or the largest value quickly. So now let's try to uh deviate away and try to
18:07:21
understand one more important principle.
18:07:27
Q is a very simple data structure where we simply follow the normal principle of
18:07:33
first in first out where let's say that we have we currently have elements come in from this way and then we have values
18:07:40
coming in 0 1 2 3 4 in this fashion then the values going out are also going to
18:07:45
be in the same fashion and we are going to have a valid lo legitimate Q in real
18:07:51
life we see many examples of Q's being formed maybe we go to banks or maybe we go to ATM camps or places to fill up our
18:07:58
gas. We follow the same principle. But the thing is many times in reality we might have some situation where uh some
18:08:06
nodes actually pro or some person actually needs to be treated little bit
18:08:12
differently little bit specially that this this is true in terms of real life scenarios like banks or places where you
18:08:19
need to go for public gathering because imagine if someone is like disabled or
18:08:24
someone is pregnant or someone there is some elder fellow then in that case we
18:08:29
try to give them higher priority compared to rest of the people who are already currently placed or already
18:08:36
currently waiting inside the line because let's say that there are four people in the line suddenly a person
18:08:41
comes in and that person may be physically handicapped. So you don't want to be that bad person to say that
18:08:47
hey buddy you need to follow the line. You actually wants to be generous enough and try to give that person the priority
18:08:54
to complete that task first. And this is what many times we have to do inside the
18:08:59
computer systems as well where we will have to uh implement some sort of data structure that typically does the work
18:09:06
in normal like uh typical Q fashion but from time to time we may have some
18:09:12
priority nodes that come in that needs higher priority or higher resources and that needs to be tackled immediately. So
18:09:19
some example could be let's say that currently I have a system like Amazon where in the Amazon I'm usually trying
18:09:25
to uh process the orders that come in in regular intervals at normal times. But
18:09:30
imagine that I suddenly realize that someone is trying to purchase a value of $50,000 and that is that might be
18:09:38
suspicious. So do I actually wants to put this order behind the queue and uh
18:09:44
leave the customer and be like that customer already placed their order and now they are just waiting for their confirmation. No, I actually wants to
18:09:51
process this order immediately because this is a high priority item that I need to get rid of. So that's why this is
18:09:57
going to have higher weightage and this would be processed first. This concept is also applied and desperately needed
18:10:06
inside the world of computer science as well.
18:10:11
Well, we already know or we already have a Q- like data structure where we follow the principle of P4. But the thing is
18:10:19
this is where using heap uh comes into the picture to actually implement
18:10:25
priority cube because remember what does heap do? Heap at any given moment can
18:10:30
say that this is currently the highest priority. If we are judging the priority
18:10:36
based on the minimum value of something or this can be the highest priority if we are trying to judging something based
18:10:42
on the maximum priority of something. In either case, if we have implemented the heap correctly, we can actually process
18:10:50
priority Q in the simplest fashion because at every single interval or every single moment, we are going to be
18:10:57
able to find out that what is the node that contains the highest priority depending on whether the minimum
18:11:02
property or maximum property we are trying to differentiate and then we are going to be able to say that this is the
18:11:08
node that you should be processing right now. Now coming back to my question why would you assume that only minimum or
18:11:16
maximum would be sufficient enough to determine the priority of any any particular node and that's where the
18:11:21
normal concept comes in where let's say that there are currently two people waiting right now and you want to decide
18:11:29
that amongst these two people which person are you going to give your groceries. Okay let's say that you are
18:11:35
currently grocery shop owner. So if there are two people what you are going to do you are going to do some sort of
18:11:41
comparison you are going to say that which person is maybe willing to pay me more money or which person is maybe uh
18:11:48
like dying of hunger and you you want to help them. So there is always going to be the game of comparison you are going
18:11:54
to be playing amongst any two available node or more than one nodes. So whenever
18:11:59
the comparison comes in one has to become the winner based on some property. So this is what heap allows
18:12:05
you to find out. It says that okay you you tell me what property you want me to judge nodes based on and depending on
18:12:12
the property whatever the value you set up you can always find out that which node contains the highest priority and
18:12:18
if there is only one node left then that one node is the highest priority because there is only one node. So this is how
18:12:25
combination of heap and prior concept of priority Q can actually give birth to
18:12:30
some of the most amazing and very fastly performing data structures and algorithm
18:12:37
items that we can do. We all know the property of heap. Number
18:12:43
one property is that heap is always going to be balanced and second property is that heap is going to have a parent
18:12:51
child relationship. So if it is going to be a min heap then parent is always going to be smaller than child. If it is
18:12:57
a max heap then parent is always going to be greater than heap or greater than its child. So let's try to understand
18:13:04
this and we will try to understand conceptually that how does implementation of heap works. So let's
18:13:09
say currently I only have one node and that is node number five. Okay. And I'm
18:13:14
trying to maintain a max heap. Now logically the core concept of a heap is
18:13:20
that you are always going to add values to the bottom place or to the last element. Then you are going to be
18:13:27
checking that whether whichever property you are trying to maintain. So currently we are dealing with the max heap. You
18:13:33
are trying to see that whether this property is followed or not. If this property is not followed because we
18:13:39
added the value at the very end we are actually going to do a sift up or bubble
18:13:44
up operation with the parent. So wherever we see that this property is not being followed, we will swap the
18:13:50
values of parent with its subsequent child. So let's say in this case the value we are trying to enter is value
18:13:56
number seven. Now we all know that seven is greater than five. So let's first add value number seven over here. Now we
18:14:02
notice that this max he property if that is being followed. No, it is not followed. So then we are simply going to
18:14:08
do a swap operation and we are going to have seven located at the top and then
18:14:13
we are going to have five located over here. Now let's say that next element we are trying to enter is going to be value
18:14:18
number three. So we will simply add value number three over here. So currently after adding this three does
18:14:24
any equation change? No. Because seven is still greater than its child three. So that's good. Now let's say that now
18:14:31
once again we want to add value number uh let's say one. Okay. So if I add one,
18:14:36
one is going to come over here. Once again this is good. Now let's say I want to add value number four. So once again
18:14:42
value number four I can add without any issues. Now once again I want to add value number uh six. So if I want to add
18:14:50
value number six over here, what's going to happen? Well, we are going to see a discrepancy between these two nodes. So
18:14:56
we will have to do a swap operation or a hep5 operation. If we do hepi operation
18:15:02
in this case then this node three is going to be replaced by node 6 and then
18:15:07
this six is going to have node number three. And notice because of this hepi operation we are actually never going to
18:15:14
be able to maintain a binary search tree because at any given moment we might have to swap with either left child or
18:15:20
right child. So that's the difference between heap and a binary tree. Now let's say that in this case we want to
18:15:26
add value number nine. So once again we added 9. 9 is definitely greater than
18:15:31
six. So we are going to do a a switch operation. So if we do that then we our
18:15:36
node value number six is going to end up over here. 9 is going to end up over here. But this is still not correct
18:15:42
because we still have a parent that is smaller than the than it subsequent child. So once again we are going to do
18:15:48
a heapy operation for bubble up and this is going to be nine and this is going to be seven. And this is how the
18:15:54
implementation of heap works in order to maintain the property of this being
18:15:59
maximum heap or this or maybe we can have same example for a min heap as well
18:16:05
and finding this property is going to be very crucial and very useful. Now let's imagine a scenario where we might have
18:16:12
to kick one element out because in the priority queue once you process the node there is no point of keeping that node
18:16:18
as the highest priority. So let's say that in this case we decide that this nine has been now processed. So once
18:16:23
this nine gets processed we will have to do the hepifi operation again. So in that case the simple thing we are going
18:16:30
to do is we are going to check that what are the subsequent child of this particular element and whichever poses
18:16:37
the greater value that value needs to be switch uh switched up. So in this case
18:16:43
seven would be shifted up but now the seven is once again empty. So once again we are going to repeat the same process.
18:16:49
we are going to find the value with the highest value. So in this case which is six. So once again this six is also
18:16:55
going to be sifted up and we are going to have this node becoming empty. So remember inside the heap whenever we
18:17:02
process a node we always have to do sifting operation but eventually the
18:17:07
node from the bottom is always going to be removed. It is never going to be that
18:17:12
node from the middle gets removed and then there is nothing and then there is an imbalance in the tree. No, it's
18:17:17
always going to be a balanced tree and we are going to maintain the heapy property very easily, very thoroughly
18:17:23
and very clearly.
18:17:29
So here is a simple implementation for min heap class and you can do the same implementation for the max heap. We just
18:17:35
have to change the condition. So let's understand that how we are going to do it. We can see that we are actually
18:17:40
going to use an array to represent a heap. Which means in an array we will have to identify that for any particular
18:17:47
given value what are going to be the parent node and what are going to be its child node. So we we will figure it out.
18:17:54
First uh this is a simple constructor to create a new instance of a min heap based on given capacity that we can
18:18:00
maintain. Now we have some helper methods that is this parent left child
18:18:06
right child and is a leaf leaf or not. So this simply identifies that because
18:18:12
we are using an array we can define that based on any given index position we we
18:18:17
should be able to identify that who is the parent of that particular index position what is its left child what are
18:18:23
the right ch what is its right child and whether that given node is the leaf node or not. Next let's learn that how we can
18:18:30
actually insert a new element inside into the heap. So for that it's a pretty simple process. First we check that if
18:18:37
the given heap is full. If that is not the case, we are going to check that what are the current elements and we are
18:18:44
also going to increase the size of the existing heap. Then we are going to do the heapify operation and we are going
18:18:51
to do the swap operation. So the logic is quite simple that because remember we are going to be adding the element
18:18:57
inside the very last position of the heap and after adding it to the last position of heap we are going to check
18:19:03
that for the current position where we are inside the heap compared to that with its parent node if we follow the
18:19:11
property of the current node being smaller than its parent node. If that is the case then we would have to do the
18:19:17
heap and bubble up operation. So we are going to do the swap amongst elements and then once again we are going to
18:19:23
repeat the same process by marking the current node as the parent node and keep
18:19:28
on repeating until we reach to uh a place where this ele this condition is no longer true. Same way if we want to
18:19:36
do the remove min operation which it's quite straightforward. We simply have to remove the very first element that is
18:19:42
currently present inside the heap. And then once again we will have to make sure that what is the current element uh
18:19:49
or the main element inside the heap. that is that we are going to find the minimum value amongst the remaining
18:19:55
child and we are also going to reduce the size of the existing heap by removing the last element and once again
18:20:02
repeatatively doing the heapify operation. So here is the condition of
18:20:07
the heapy operation we already talked about where we are going to check amongst the left child and right child
18:20:13
for any given node to make sure that whether we need to do the hepifi and are we following the property of min heap or
18:20:20
max heap depending on whatever the values we are given. So this is that logic that we just saw inside the um
18:20:27
construct inside the expl inside the conceptual overview of the heap and uh
18:20:34
same way we have a very simple swap method that is just to swap two elements. This is a pretty elementary
18:20:39
method. So this completes all the items we need to implement our heap. And then
18:20:45
we are going to have our main method where we are adding bunch of different entries inside the heap which we can
18:20:51
see. And as we know that since this is a min heap, we are trying to fetch the
18:20:58
minimum value of this particular all the values that we have inserted. Now we can see that so far the minimum value is
18:21:05
three and which is what we should be returning based on our heap operation. Let's try to run the code and we can see
18:21:12
that the value returned is min uh three. So which means our class works fine.
18:21:21
Okay. Now we understand all the way on how implementation work. What is heap?
18:21:26
What is priority Q? What is tree? What is binary tree? Binary search tree. Differences of each one of them. Now
18:21:32
let's try to understand that what are the benefits or under under which type of scenarios should you start thinking
18:21:39
about using heap. So number one benefit of heap is that at any given moment you can identify that what is the element
18:21:46
which contains the highest priority and you can work on that. So whenever you are dealing with any question related to
18:21:53
priority you always have to make sure that you are following or you can try to
18:21:58
think that hey in this scenario can I use a heap or can I use a priority queue to solve this problem and more like more
18:22:04
than likely you would be able to solve this one. Next thing is you will also have to understand that at any given
18:22:11
moment you are being told that what is the k highest element or kth lowest
18:22:17
element or something like this. So K maybe some anything with K. So and this K can be like third highest, fourth
18:22:24
highest like third lowest, third biggest, third largest, third smallest. Whenever you see any particular type of
18:22:31
this type of condition in that case that answer has to be solved using a min heap
18:22:36
or max heap. Now the question is when to use min heap and when to use max heap. I'm I'm going to give you a shortcut
18:22:43
that is going to be very much helpful to you. Imagine that let's say currently I have these five elements that are given
18:22:50
to me right and they are just placed in random order and I don't know which is which currently these are the five
18:22:57
values now the question is I tell you that find me the third largest element
18:23:03
okay so which means the logic is or not third but let me give you uh the question for let's say second largest
18:23:09
okay this would make more sense so if I want to find second largest element so
18:23:15
Then because we are trying to find largest element as in biggest element.
18:23:20
So the idea is that we whenever you want to find big or find bigger element or
18:23:26
larger element try to build the min heap. Okay. Do the reverse. Okay. And
18:23:32
why we will do that I will also explain it to you. Do the reverse. So build a min heap. And of what size? It has to be
18:23:39
of size two. And now let's try to uh do our logic that I'm suggesting. So
18:23:44
currently we have our min heap of size two. Now the only thing we are going to do is whenever we realize that there is
18:23:51
a new value we need to bring in and that new value is actually greater than the
18:23:56
very first element we currently have. Then we are going to pop one value out and we are going to push that value
18:24:02
inside and the automatically heap will maintain. You will see what I mean right now. So let's say currently we have
18:24:08
value number five. So currently we are maintaining the min heap. So five is the smallest element we find. Next is value
18:24:13
number seven. Okay. So once again we are trying to find the min heap. So once again uh seven is going to play be
18:24:19
placed later. Okay. Currently we had space inside the heap. Now let me also
18:24:25
make some changes. Okay. This one is eight let's say and this one is value number nine. Okay. Now we have value
18:24:31
number one coming in. So should one come in? Currently heap is full. But the thing is this one is actually smaller
18:24:37
than the very first element. If it is smaller then we don't pro care about one then we get rid of one. Okay. Now this
18:24:43
nine comes in. Once again this nine is actually greater than the very first element we have inside the main heap. So
18:24:49
we are actually going to kick this element out and we are going to we should be placing nine in. But now once
18:24:56
again the proportion of heap is going to change. This is going to become seven and this is going to become 9 because
18:25:02
currently seven is the small smaller element out of these two and this is a
18:25:07
min heap. Once again we have element number eight coming in. So once again for this one we see that 8 is greater
18:25:13
than seven. So seven needs to be kicked out. Now where does 8 fit in this case?
18:25:19
So 8 is actually going to fit over here. And notice that by doing this operation
18:25:24
we actually did find a min heap of size two. We are trying to find the second largest element and the second largest
18:25:31
element is going to be the first smallest element inside our min heap.
18:25:37
That's it. This is the whole solution. You just find out you just figured out that how does the solution work and we
18:25:44
did did what we wanted to do. You know the funny thing is even if we did not apply this property of like fetching the
18:25:52
largest value out still we would have ended up with this example and this option. So this is one of the very po
18:25:59
powerful way where you can start to think about using heap in order to solve off solve all of your problem and these
18:26:05
are some of the most common type of problems inside the heap.
18:26:12
So logically the number one operation we can do is that we can add elements inside the heap. That is a simple task.
18:26:19
Second option is that we can actually uh remove element from the root. So we can
18:26:25
actually figure out that which is the smallest value and which is the largest value and this uh remove element
18:26:32
removing element from the root is typically done in nearly constant time. So we go of one time we can do this
18:26:38
operation. Now adding or actually adding is actually done in go of log time. Why
18:26:45
login time? Because we have to do the hep5 operation. So that's why it takes login time and even for the removal we
18:26:51
can figure out the value in big of one time. But once again after removing we have to do the HP5 operation. So that
18:26:57
could potentially take big of login time. So in the worst case scenario it is typically big of log login. In the
18:27:03
average scenario it's usually going to be big of one or around that time. Now the thing is if we have to do a search
18:27:09
operation that whether any element is present inside the heap or not. This is an expensive operation because we don't
18:27:15
maintain any order inside the heap. All we know is that whether the parent is going to be larger or smaller than its
18:27:21
child but we don't know that what is the packing order where does the value lies. So in the worst case scenario this can
18:27:27
operate in big off end time. So you will have to be careful about that that you should only be using heap when you are
18:27:34
dealing with some sort of priority. And if you have some other operation like searching or things like that then maybe
18:27:40
try thinking about using a binary search tree or some other type of sorting mechanism because that is going to be
18:27:46
much more helpful. And now after this uh if you have to remove or if you have to
18:27:52
delete any specific element then that is also going to be once again big of n because you will have to first search
18:27:58
that where that element lies and then removing that and this is it. So now I
18:28:05
hope that you understood that what is heap, what is priority Q, what are the differences, commonality, benefits,
18:28:12
drawbacks under what type of scenario should be using it.
18:28:19
So the lead code problem we are going to do is called last stone weight. Now in my opinion this is one of the most
18:28:24
awesome problem I have seen. We can see we can see that this one is an easy problem and also a very well-liked
18:28:29
problem. The problem statement is that we are given an array integer of stones that defines the weight of every single
18:28:36
stone that is currently present. Okay. Now we are playing a game with these stones. Now during the each turn we
18:28:44
choose the heaviest two stones. So this is the important part. We choose the heaviest two stones and then smash them
18:28:50
together. Now the question is there can be two possibilities. One possibility is
18:28:56
that uh either for two stones X and Y either both are of same weight or both
18:29:02
are of different weight which means one is heavier than the other. If both are of same weight then both stones get
18:29:09
destroyed. Okay? Because we are smashing them together both stones get destroyed. If that is not the case and if we
18:29:14
realize that one stone is heavier than the other then the stone with lesser
18:29:20
weight gets completely destroyed and the stone with higher weight has a new
18:29:26
weight that is like y - x. So whatever the difference between weight is between
18:29:31
two weights and then we are going to keep on repeatedly going to do the same process uh until the end of the game
18:29:38
where there is only one single stone left and then we are going to see that what is the stone of what is the weight
18:29:45
of that particular stone and that's why the name is last stone weight. Now let's try to understand this with an example
18:29:51
so it would make more sense. Currently we are given an array where every single value represents the weight of uh stones
18:29:59
at that particular position. What is what are we being told that we need to find the two heaviest stone during every
18:30:05
single iteration. So currently two heaviest stone is stones are going to be 8 and 7. So currently 8 and 7 are not
18:30:12
equal to each other. Which means when these two uh stones get smashed, this seven is going to completely be
18:30:18
destroyed. And this stone 8 is actually going to be only of size one because we
18:30:24
will have to do 8 minus 7. Okay. Following this particular condition. So
18:30:30
once again if we do that currently we have this seven gets completely destroyed and we have this element
18:30:36
number eight that is now being turned into element number or stone weight size one. So now the new array we have is
18:30:44
values 2 4 1 1 and 1 and three. Once again we are going to repeat the same
18:30:50
process. So find the two heaviest stones that are four and three. Once again both are not same. So once again if four and
18:30:57
three gets collided we are going to left with one stone that weighs 1 kilg and
18:31:02
the stone number three is going to get destroyed. So the new array we are going to get is going to look like this where
18:31:08
the values are 2 1 1. Okay. So once again in this case now this two and one
18:31:15
are both are the stones. So they both are going to be crashed against each other. So if we do that once again this
18:31:21
stone will get completely destroyed. This one only becomes of weight one. So new value is going to be one amongst
18:31:27
these two and then these uh three ones we already had. Okay. So now once again
18:31:33
we are going to repeat the same process. Now two heavy stones are both contains the same weight. If the weight is same
18:31:39
both gets destroyed. So in the next iteration we are only left with two stones one and one. And once again if we
18:31:45
try to smash these two stones together both will also get destroyed. So we will
18:31:51
not have any stones left in this case. So we will need to return zero. Now let's say in the same condition let's
18:31:57
take one more example where we try to have some weight inside the stone. So
18:32:02
let's say the values are now in this case currently the two heavy stones are this eight and six. If both gets uh uh
18:32:11
smashed then we will have values with two three and four. Six will get destroyed. So once again the two heavy
18:32:17
stones are three and four. So once again if both get smashed then this three is going to be destroyed and we are going
18:32:22
to be left with values two and one. If these two get smashed together then this one is going to get destroyed and last
18:32:28
stone will only be left with size one. And this is what we need to return as
18:32:33
the answer. So basically this is what the problem statement is asking us to solve.
18:32:40
The brute force approach is actually going to be quite straightforward where at every single iteration we will first
18:32:46
have to find the two heaviest stones. Once we find the two heaviest stones then doing all the remaining work is not
18:32:53
that much complicated. Then we can simply find the difference between them and then once again create a new array
18:32:58
and then once again uh try to repeat the same process until we are only left with just just one stone or no stones at all.
18:33:05
So brute force approach would yield us the correct result. But the issue is for
18:33:11
every single time if we have to find the two heaviest stones for each of the
18:33:16
remaining array basically we are going to be doing big of n square work just to find the two heaviest stones and once we
18:33:23
do that solving this problem is very simple and very easy to do.
18:33:29
So the question we will have to focus on is that how can we improve upon the
18:33:34
scenario where finding the two heaviest tone becomes very convenient for us at
18:33:40
every single iteration. And for that the idea is whatever the in given input array is we will actually try to create
18:33:47
a priority cube or a heap where we are going to store all the values and we are
18:33:53
going to set up this heap to be of max heap type. So max heap means that
18:33:58
whenever you try to add the values inside the heap, it is going to store the maximum element first and then uh
18:34:04
smaller elements later which means it is going to store all the values inside the descending order. Okay, this is the this
18:34:11
is the whole concept of max heap. So that's what we are going to use in this problem. And let me quickly show you
18:34:16
that using max heap this problem becomes really easy to solve. The idea is that first currently we are simply going to
18:34:23
iterate over every single values and start putting them one by one inside the max heap. If we do that we will get a
18:34:30
sort of u I would say uh a value that is sorted in decreasing order. So very
18:34:37
first element is going to be value number seven and then we will have value number six and once again then we will have all the subsequent values uh in the
18:34:45
same decreasing order and this is the input we currently have. So once after
18:34:50
finding this input for in order to find our x and y values we simply need to pull these two values in and after
18:34:57
pulling these two values all we need to do is find that if they are of same size
18:35:03
then destroy both of them and move forward. If they are not of the same size find that what is the delta between
18:35:09
them and whatever the difference is try to put that back inside the max heap. Keep on repeating the same process until
18:35:15
we are only left with just one element. And let's try to see the solution I'm proposing in in action. So once again in
18:35:22
this case currently this is our max heap and currently these are the two largest
18:35:27
elements 7 and six. We will try to pop them out and we find that the difference is going to be one. Okay. So currently
18:35:33
this seven and six has been popped out and we have element number one that needs to be added. So in order to add
18:35:38
element number one it will be added uh in the back side of the heap. So we will
18:35:44
uh let I will not draw a new heap. I will just keep on adding one values. Okay. And these are just empty shells.
18:35:50
So don't just ignore them. Now once again during the next iteration we are going to find the two heaviest elements
18:35:56
that are four and three. Once again the difference is going to be one. So once again now we no longer have values four
18:36:02
and three inside the heap and we are just going to add one more element one at the end of the heap. Next two heavy
18:36:08
elements are two and two. So because both are same so we are simply going to ignore them and not add any other
18:36:14
values. Now the two heavy elements inside the given heap are 1 and one. Once again both are same so we are going
18:36:21
to delete both of them and don't do anything. And lastly there is only going to be one stone left that is going to be
18:36:28
of size one. And this is what we need to return as the answer. So you realize that after storing all of this
18:36:35
information inside a heap that is a selfbalancing data structure that automatically sorts itself with new
18:36:42
elements being added. How easy this problem becomes. So once we start once we implement the heap this problem is
18:36:48
very simple and we know that insertion inside the heap takes log n time and we will have to do it for n given input. So
18:36:55
it's going to take n login to store all the values and complete this problem. So this is going to be the time complexity.
18:37:01
If we see space complexity that is going to be bigo of n because we are s we will
18:37:06
have to create a new heap to store all of these values. So there is no other way to move around that. But still this
18:37:12
is a very good time and space complexity. Now let's try to quickly see the coding solution for this one.
18:37:20
Okay. Okay, so first of all we are going to initialize our max heap and this is how we actually initialize it using the
18:37:26
priority Q and in the comparator class we are mentioning that only the maximum element has to be uh at the beginning of
18:37:32
the heap. Then we are going to add all the values inside our max heap and then we are going to continuously remove and
18:37:39
smash the two heaviest objects until we are only left with just one element. And for that we we find our y as the very
18:37:47
first element inside the heap. we find our x as the second element inside the heap. We simply have a condition that if
18:37:53
x is not equal to y then we are going to add and add the element that is the
18:37:58
difference of weight between y and x elements back inside the heap and keep
18:38:04
on repeating the same process while the size of the heap is greater than one. And the moment we reach to the end we
18:38:11
are simply going to check that if the heap is empty we are going to return zero. If the heap heap is not empty, we
18:38:17
are going to pull the last remaining element inside the heap as the answer and that is going to be the heavy last
18:38:23
remaining stone weight uh of our original input of stones that we were given. So now let's try to run the code.
18:38:37
Team server solution is working as expected. Let's submit this code.
18:38:43
and our code runs 98% faster than all the other solutions. That in itself
18:38:48
suggests that we are doing something really good and really right. So once again this coding solution is present
18:38:54
inside our GitHub repository. You can go and check it out from there. Thank you.
18:39:10
So the lead code problem we are going to solve today is called k largest element inside an array. And we can see that
18:39:16
this one is a lead code medium problem or also extremely well-like problem. Now in my personal opinion this should have
18:39:22
been an easy problem but anyways they have put it as medium. So let's be let be it. Uh we are given an integer array
18:39:28
nums and we are also given an integer k. Basically we need to return the kth largest element that is currently
18:39:35
present inside the array. Now let's try to understand this with an example. Suppose this is the input we are given.
18:39:41
We can see that there are bunch of different random values present at the random location. Now let's say for this
18:39:47
problem we are given k is equal to 3. Which means we will have to find the third largest value that is currently
18:39:52
present inside the given array. Now we can see that the largest element is seven. So that is the first largest
18:39:58
element. Six is the second largest element and four would be the third largest element. So in this case we will
18:40:04
have to return four as the answer as the third largest element. Now let's try to find that what are the different
18:40:10
approaches we can take to solve this problem.
18:40:15
First approach comes to our mind is a brute force approach where the idea is quite straightforward. We simply iterate
18:40:20
over the given input array simply one by one and in order to find the maximum
18:40:25
value. Then once again we iterate over in order to find the second maximum value and we iterate over the third time
18:40:32
to find the third maximum value until we reach to the kth maximum element and we
18:40:38
return that this value as the answer. Obviously you can see that we are doing lot of repeated work with the brute
18:40:43
force approach and the time complexity is going to be big of n multiplied by k.
18:40:48
So that is not a good approach. Let's try to find the second solution.
18:40:55
Now second solution is quite straightforward that for this given input if we somehow sort this given
18:41:02
input then finding the k element is very easy because then we will know that
18:41:07
after sorting this the largest element is going to be for the the first one and then we will be we will have values
18:41:14
stored something like this one where we can easily find that which is the third largest element in just like uh just
18:41:21
like that. So uh sorting will take big go of n log n time and then finding this
18:41:26
element will only take big go of k time or just like this would be instantaneous because it's an array. Okay. So overall
18:41:34
this is a good approach works fine but the issue is we are explicitly told that we need to solve this problem without
18:41:40
sorting. So let's try to see that how can we actually solve it without sorting.
18:41:48
For that we actually have two options. First option is that we find the most
18:41:54
optimal way to solve this problem that is using a priority cube or a heap. That
18:41:59
is one way and second option is that whether we use a quick select algorithm.
18:42:05
So let me know in the comments if you want to see the quick select approach. Uh I can also make a video on that in
18:42:11
the future. But in this time we are simply going to use a heap. The idea is we need to find the kth largest element.
18:42:18
So we are actually going to store a min heap where we are going to store all the values in a min heap fashion which means
18:42:26
in a ascending order. Okay. So the very first element inside the min heap is going to be the smallest and then all
18:42:32
the other values are going to be larger than that. Next thing is we are going to have this min heap of size k. So we are
18:42:39
only going to store k values at one time. And third thing is that in this particular min heap we are going to have
18:42:45
a condition that let's say if a new value we are trying to add if that value is x if that value is greater than the
18:42:53
very first value we currently have present inside the min heap then we are going to kick this value from the min
18:42:59
heap out and try to put x inside the min heap. So min heap once again is going to maintain its sorting property and it is
18:43:06
going to keep all the values inside the min heap or ascending f fashion. So let's try to see the solution in action.
18:43:13
So let's initialize our min heap. So currently the given k is equal to three. So the size of the min heap is only
18:43:19
going to be three. Very first element is value number four. The second element is two. So once again we are going to store
18:43:26
the values inside the ascending fashion. So two and four. Next element is six. So six would be added over here. Okay. Next
18:43:32
value we are trying to add is value number one. So once again one is a smaller value. So if one value is
18:43:40
smaller than current max minimum heap then we don't need to do anything we can
18:43:45
simply skip over why because we know that in this particular fashion the
18:43:51
third largest element is actually going to be the very first element inside the heap and that is still going to remain
18:43:57
two. So we don't need to add value number one. Uh and we can simply skip over. Now we are at value number seven.
18:44:04
So seven is greater than the very first value inside the min heap. So we will have to kick this value out and then we
18:44:10
will have to put seven in. But seven would not be put in the place of two. Once again we will do the operation of
18:44:16
self adjusting the min heap. So values are going to be four 6 and 7. Once again after adding seven we have value number
18:44:22
three. So once again three is actually smaller than value number four. So we don't need to add three. Once again we
18:44:28
have value number two. Two is once again smaller than value number four. Which means we don't need to add two as well.
18:44:33
So after the end of iterating over the entire array, the very first element inside the min heap has to be the kth
18:44:41
largest element which we can see over here that this four is the third largest element inside our array and that's it.
18:44:48
So this is how easy it is to solve this problem using a min heap and we can
18:44:54
simply come up to the solution very quickly very easily without any delays. So let's try to calculate the time and
18:45:00
space complexity. In this case, the time complexity is going to be that we will have to iterate over every single
18:45:05
element and for that we will have to insert the values inside the min heap or do some sort of checking. So for end
18:45:11
times we will have to do log end work. So it's still going to be the n login
18:45:16
time. Uh it's still same as sorting but the thing is rather than sorting we are using a priority Q to take care of the
18:45:24
values inside the priority fashion inside the min heap fashion. If we see space complexity in this case, space
18:45:30
complexity is going to be big of K where K is the size of the given K element we are trying to find because we are
18:45:35
initializing a new min heap to store the value. So it makes absolutely good sense to store this one. So we can see that
18:45:42
this one is a really good time and space complexity to solve this problem. And once again as a general rule of thumb
18:45:48
whenever you find any question where you want to find k smallest element or kth
18:45:53
largest element or kith biggest element something like this whenever you see kth
18:45:59
try try to see that if you can use a heap to solve this problem and almost 99% of the time you should be able to
18:46:05
solve this problem. Okay so now let's quickly see the coding solution for this one.
18:46:13
So this is the coding solution. We can see that this is very simple and short coding solution. Basically, we first of
18:46:19
all initialize our priority Q or min heap and then we have a for loop to
18:46:24
iterate over the given input nums that is provided to us where we are simply going to add these values inside the min
18:46:31
heap one by one. Then we are going to check the for a condition that if the size of min heap is greater than k then
18:46:38
we need to pull the very first element that is present inside the min heap and that's it basically. So in the end we
18:46:45
should have a min heap that only contains the kth largest element at the very first position that we are going to
18:46:52
do a peak operation and return and let's try to run the code.
18:46:58
Okay, seems like our solution is working as expected. Let's submit this code.
18:47:04
So our code runs faster than lot of other solutions and uh this is a really good approach. So I would be posting
18:47:11
this solution inside our GitHub repository.
18:47:23
So the lead code problem we are going to solve today is called K closest points to origin. Now we can see that this one
18:47:29
is a lead code medium problem and also a very well-like problem on lead code. The problem statement is quite
18:47:34
straightforward. We are given an array of points that represents points on an XY plane or a graph and we are also
18:47:42
given an integer k. Now we need to return the k closest point to the
18:47:47
origin. Now we are also given that what is the mathematical equation to point
18:47:52
the distance between any two points and that is the ukidian distance formula. So that is x1 - x2 square + y1 - y2 square
18:48:00
and square root of the whole thing. So we need to say that okay say for an
18:48:06
example if this is the input we are given we can see that there are bunch of different points presented to us. Now I
18:48:12
have plotted these points on this graph and we need to return the k closest
18:48:17
point to the origin. So origin is going to be this point 0 0. So origin point is always going to be 0 0 and we need to
18:48:24
use the ukidian formula. So let's say that we are given k is equal to 2. So we need to return that what is the second
18:48:31
closest point to the origin. So we can see that in this case this is going to be the first closest point to the origin
18:48:38
and the second closest point is going to be this one. So we need to return uh this value uh two and one as the answer
18:48:46
as this is the second closest point to the origin. Now in order to calculate the distance between any two points
18:48:51
let's say that we wants to calculate this distance between this 1 one point and 0 0 point. So the mathematical
18:48:58
equation is going to be uh 0 minus the whatever the x square is that is x - 1.
18:49:04
So 0 - - 1 and the square of this one plus once again we will take y1 - y2 so
18:49:13
0 - uh this one is 1. So 0 - 1 and the square of whole thing and then we are
18:49:18
going to do the square root of this whole thing. So that is going to give us this distance that since in this case we
18:49:23
are given k is equal to two we need to find the second closest element uh in
18:49:29
order and return that as the answer. So in this case the answer is going to be 2 and 1 that we need to return. So that's
18:49:36
it. This is the whole thing that what the problem is asking us to solve.
18:49:43
So brute force approach is actually quite straightforward. In the brute force approach, what we can do is we can
18:49:49
simply start calculating all of these distances that are currently given to us. And then after calculating all of
18:49:56
these distances, we will have some random values because for sure we are not going to get exact values because we
18:50:03
don't know which one is the closest, which one is the farthest. Let's say we find some random values like let's say
18:50:08
that this one is three, this one is two, this one is one. I'm just giving some arbitrary values. Okay. So something
18:50:13
like this. Then uh once again amongst these values we will have to find that what is the second closest value. So
18:50:20
once again for that we will have to iterate over the given array and find the second closest value. In order to do
18:50:25
that it will it can still take big of n square time in the worst case scenario. So we will have to do something better.
18:50:35
So here now for the optimal solution I have just put down like every single point uh denoted as a number and for
18:50:42
that number I have calculated that what is going to be the distance from the uh
18:50:48
origin point for that particular value and I have marked all of these values over here. Now say for an example just
18:50:54
for understanding sake we will try to now on understand that this one as if it
18:51:00
does not contain a square root. Okay, this is just going to help us understand that what the solution is look like and
18:51:05
how we can use max heap in in this case to solve the problem. The idea is that we are going to create a max heap of
18:51:12
size K and inside the max heap we will always try to first add the value inside
18:51:18
the max heap and the moment we realize that the size is actually greater than K then we will have to pull the lastly
18:51:25
added element outside of the max heap. Okay, we are only going to store the K values. So in this case we are trying to
18:51:31
find the second closest point to the origin. So k is equal to two. So let's say uh let's quickly initialize our max
18:51:37
heap and inside the max heap currently we don't have anything. Now in the max
18:51:42
heap we are only going to store two elements. Okay I'm just adding one more element over here because this is we
18:51:49
will put put down the buffer value to see if we exceed the size of the max
18:51:54
heap. If we exceed we are going to pop this element out. Okay. So now let's try to populate our max heap with the theory
18:52:00
we just mentioned. So first we have value number seven. So we are going to put value number seven. Then we have once again value number seven. So we are
18:52:07
going to put value number seven. Once again we have value number two. So once again we are going to we will have to
18:52:12
adjust the input. So it's going to be seven and then seven and then two. But we exceeded our place because uh we only
18:52:19
want to store two elements. So we are going to kick the seven out and we are going to leave this is as it is. Then we
18:52:25
have value number five. So once again this needs to be readjusted. So values are going to be seven and then five and
18:52:30
then two. But once again we exceeded the number of input. So we will have to kick the seven out. Now we only have value
18:52:36
number five and two. Once again we have value number six. So six would come over here because this is a max heap. So we
18:52:41
are following the property of descending order coming to the first. So the maximum value is being is going to be
18:52:47
stored very at the very top. And then once again we will have to kick the six
18:52:52
out because we only wants to keep k is equal to two elements. Lastly we have value number three. So once again first
18:52:57
we will do the readjustment. So values are going to be 5 3 and 2. But once again this five is accessed. So this
18:53:03
will also be kicked out. And then we are now done with all the values. And now we
18:53:08
only have these two values inside our max heap. And the very first element inside the max heap has to be the kth
18:53:16
closest element to the origin. And which we can see because this is the end point
18:53:21
and the distance is square root of three. And we can see that this is actually the second closest point to the
18:53:26
origin after this one. So this is what we need to return as the answer. And uh this is the whole solution. So basically
18:53:34
the important portion in this one is that first this problem looks complicated because we are dealing with
18:53:40
like XY graphs and I don't know I know many people after high school haven't even dealt with this one plus you might
18:53:46
have forgot about the ukidian distance equation but don't worry these are all just the constant matter. So all we need
18:53:53
to do is number one we are going to iterate over the given input and we are going to find that what has been the
18:53:59
ukidian distance from every single point to the origin using a simple mathematical formula that is x1 - x2
18:54:08
squared plus y1 - y2 squared and the square root of the whole thing. Okay,
18:54:14
after doing this one, we simply need to initialize our max heap to the values or size of K and we are simply going to do
18:54:21
the operation that we just mentioned. In the end, we can simply do max heap dot peak operation and that is going to
18:54:27
provide us the k closest point to the origin and that's it. This is the whole solution. So now if we see time and
18:54:34
space complexity in this case time complexity is actually going to be big of n log n because it takes login time
18:54:40
to enter values inside the heap and we will have to do this n times plus we will also have to spend some time
18:54:46
calculating the distance from the origin to that particular point but that is going to be constant effort that needs
18:54:51
to be done for n values. So we can simply ignore this one because it is no longer relevant because we already have
18:54:57
a higher time complexity component. space complexity once again we will have to create an extra heap so that is going
18:55:04
to be big of K. So now let's try to see the coding solution for this one.
18:55:11
So the coding solution is actually quite straightforward. We are first of all going to initialize our max heap and
18:55:17
inside the max heap we are going to store the values based on the distance from the origin to that particular
18:55:24
element and that is going to be done based on using the ukidian uh distance
18:55:29
formula from the origin and once we have that those values sorted then all we
18:55:34
need to do is just simply add those values inside our heap. Now inside the heap we will first add the value then we
18:55:41
will check that if the size of heap exceeds the value of k we are going to pull the very last element we entered
18:55:47
inside the heap and that's it. Now in the end we simply need to collect the clo k closest point from the heap. So
18:55:55
for that we can simply create a result uh uh array 2D array and we can simply
18:56:01
run from I to the K and we will try to find the element and then we will pull it inside the result and then we can
18:56:08
simply return that as part of the result. So that this is the whole solution. Now let's try to run the code.
18:56:17
Okay, seems like our solution is working as expected. Let's submit this code
18:56:23
and our code runs pretty fast compared in terms of time complexity and extremely good in terms of space
18:56:28
complexity. So once again the solution is present in our GitHub repository. So if you want you can go ahead and check
18:56:34
it out from there. Thank you.
18:56:42
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do a lead code premium
18:56:48
problem. High five and uh the though it seems like an easy problem this actually
18:56:54
covers a pretty interesting topic that is asked by a lot of fang companies uh and the topic is max heap min heap.
18:57:01
Let's understand the problem statement. Essentially we are given a two-dimensional array that looks like this where we are given ID and score for
18:57:09
different students uh that are studying in a class. Now we are given at least
18:57:15
five scores or more for every single students uh and which we can see over
18:57:20
here that over here we are given two ids. So the ids we are given are student
18:57:26
ID 1 and student student ID 2 and for student ID 1 we are actually given the
18:57:31
results of six different scores and for student ID 2 we are given the results of five different scores. Now our aim in
18:57:38
this case is to calculate the average for top five subjects. Uh so this is
18:57:45
really important that we need to calculate the average of top five subjects. So in this case since we are given six scores we only need to choose
18:57:52
the top five scores and not all six of them. So this is a key point to understand and we need to build a
18:58:00
two-dimensional array in the result and we need to return uh the result for
18:58:06
every single ID. So ID number one and ID number two in this case we need to
18:58:11
return whatever the average we have found for top five subjects and we need
18:58:16
to return them in an increasing order based on whatever the given ID. If we take a look at this example, in this
18:58:23
example for service ID number one, we are given following scores.
18:58:30
Since we are given six scores over here, we only need to choose top five. So we are not going to choose this score
18:58:37
number 60 because that is the lowest out of all and we are going to choose the remaining five scores. So essentially we
18:58:42
are going to do a sum of all these uh scores and we are going to divide it by five.
18:58:48
So that will give us the average of top five scores for this one. And for uh
18:58:54
student ID number one, the average would be
18:58:59
87. Now we need to do the same same calculation for student number two. Now in student number two, it's a little bit
18:59:05
easy because we are only given uh five dist different scores and we just need
18:59:11
to do some of those. So we don't have to eliminate any score. We can simply do some of those.
18:59:19
to 88. So now and now we have reached the end of all the student ids and we
18:59:25
have found the average. So in this case we are going to return a two-dimensional array like this
18:59:36
and this would be our answer. So the first approach we can use is we
18:59:43
can actually sort the given input and we can sort the given input based on uh ID
18:59:50
and after we are done sorting it with using ID we can sort it for every single ID we can sort it using uh score. So
18:59:58
that will make our lives easier and uh suppose we are dealing with the same input. So we can sort this input uh as
19:00:08
mentioned based on ID and score and this would be the sorted input.
19:00:16
Okay. So now since we have the sorted input, it becomes pretty trivial that how we are going to actually solve it.
19:00:22
We are simply going to iterate over the sorted array and for every single ID we
19:00:27
are only going to iterate over it uh just five times. So whatever top five
19:00:33
values we found uh we can keep on adding those top five values. uh once we have
19:00:38
once we reach end of the loop and we we are done with the top five values, we are going to divide it with whatever the
19:00:45
sum we have found with value number five and that would give us the average of
19:00:50
that particular ID and then we will move then if for that ID if more entries
19:00:57
exist we are just going to ignore all of those cases and then we will simply switch on towards new ID and we are
19:01:03
going to keep on repeating this process. So let's see that in action.
19:01:08
So basically for id number one we are simply going to uh iterate over.
19:01:16
So we are going to find top five values which are these values. We are going to keep adding them up and uh
19:01:25
after that we will divide it with five. So for ID number one we are going to find the average as 87.
19:01:32
And then once we are at this stage and we have already calculated the average.
19:01:38
If we keep iterating over our array, we are going to find that there exist one more entry with ID number one which is
19:01:44
the 60. And because this is already sorted and we have already calculated
19:01:49
the top five entries that we could find over here, we don't need to use this case. So we can simply ignore the
19:01:56
scenario and we would move forward up until we will find the next ID. Now in
19:02:01
this case we will find the next ID over here this ID number two. So again for ID number two we are going to do the same
19:02:07
process. We are going to iterate over first five elements and we will keep on doing the sum of their scores and once
19:02:15
we re once we get the score we are simply going to divide it with five. So even for ID number two we are going to
19:02:22
keep adding all the values divided it by five and we will find the average for ID
19:02:28
number two to be 88. Now since we have both of these answers stored we can
19:02:33
simply return and we can we will simply keep on adding a 2D keep on adding these
19:02:39
values to a two two to a two-dimensional array and we will simply return this at
19:02:45
the end. Uh so this would be 87 88 and this would be our answer. Now we can
19:02:51
notice over here that because we had the sorted input it becomes pretty easy for us and we can simply iterate over the
19:02:57
sorted array just once and then we will be able to uh generate this answer. Now
19:03:02
if we calculate the time and space complexity in this case well the time complexity for this case would be uh
19:03:09
actually n log n uh and the reason it's n login n is because though iterating
19:03:16
over this input uh this sorted input is only n work but the thing is we will
19:03:21
have to first from this input generate the sorted input and that actually takes
19:03:26
big go of lo n login time and that is why The overall time
19:03:32
complexity is going to be n login and if we see the space complexity in this case it would be bigo of n as well because we
19:03:39
are creating uh an additional sorted array where we are storing all these values. Now in terms of time and space
19:03:46
complexity the next approach I'm proposing is also going to be the same
19:03:51
time and space complexity. So if you want to end your video you can end it over here. There is nothing more optimal
19:03:58
that is coming your way.
19:04:03
So essentially in the given input we are basically given two things ID and score and the most critical part to solve this
19:04:10
problem is actually to identify top five scores uh for every single ID. Uh and
19:04:18
in order to achieve that we have already tried sorting method like but the thing is there exist a better approach and in
19:04:24
that better approach what we are going to do is we are going to create a hashmap.
19:04:29
Now inside the hashmap uh we are going to treat id as key. So key would be ID
19:04:36
and inside the values we are going to keep track of whatever the scores we are given for this given input. The thing is
19:04:44
the way we are going to keep track of the scores is actually a little bit interesting. We are actually going to
19:04:49
keep track of scores in an uh decreasing order.
19:04:54
So the way we are going to keep track of uh the scores in decreasing order will allow us to identify the top five scores
19:05:02
in this case that essentially for this scores we will have uh some sort of Q or
19:05:07
list and we only need to select first five element and we can ignore rest of them. So let's see that what I mean. So
19:05:14
suppose in this case we starts iterating over this uh this input and we will
19:05:20
first of all check that whether ID exists in this new uh hash set. If it does uh we will update the value in the
19:05:26
score. If it does not exist we will add the value. So initially we find that the ID is one. Now ID number one does not
19:05:33
exist. So we will create an entry over here that ID number one. And now the score we are given is 91. So we will
19:05:39
just enter the score. Now again we identify ID number one and ID number one exist. Now the score is 92 which means
19:05:46
uh that inside the scores we are putting a condition that we are only going to keep the stores in a decreasing order
19:05:53
which means that now we will have have to update the score like this. Again we find ID number two. Now ID number two
19:05:59
does not exist. So we'll have to make an entry and score is 93. Now again the
19:06:04
score is 97. So again since we are keeping track everything in decreasing order. So we will have to uh replace the
19:06:12
values. Now again id number one. Now this is 60. So 60 can directly be
19:06:18
appended at the end of this uh whatever data structure we have. Now uh we have
19:06:23
77. Again we can append 77 over here. This one is 65 for ID number one. Now 65
19:06:29
needs to go in over here. So we will have to update the value like this. And
19:06:36
now this one is 87. So next value is 87. Again we will have to update the value
19:06:41
like this.
19:06:47
Now next value is 100. So for 100 we will have to update all the values.
19:06:55
Now even for ID number two we have 100. So we'll have to update all the values.
19:07:01
Last one is 76. So we can simply append that value uh to at the end.
19:07:07
And now essentially we have iterated over this input. We have created this new data structure. If you see the
19:07:14
qualities of this new data structure, it serves our needs. Essentially we are given ids. Now if you see the ids, they
19:07:21
are sorted in u increasing order. So initially this is ID number one, ID
19:07:27
number two. If we had ID number three over here, it would be placed somewhere at the bottom. If we see the number of
19:07:33
scores we are given for this ID number one we are given six different scores
19:07:39
but thing is they are all in decreasing order which means that since we are only
19:07:44
worried about top five scores we only need to select first five entries and whatever the remaining values we can
19:07:51
simply ignore that. Same we are going to do for this value number two that we are only concerned with this top five values
19:07:56
and if there existed any other values we would have ignored that but that is not the case in this scenario. And now it
19:08:02
becomes really easy for us to identify that what is the average of these five values and we can simply do the sum of
19:08:10
them and divide it by five and whatever average we find we can just create our answer two dimensional array and we can
19:08:17
simply put it over here. So that for value number one the average is going to be 87. For value number two the average
19:08:22
is going to be 88. And this would be our final solution. Now if we see the time complexity and space complexity in this
19:08:28
one. Uh first we will have to identify that how we are going to implement all of this over here. And the way to
19:08:36
implement this is this is actually a hashmap. But the thing is we are directly not going to use hashmap. We
19:08:43
are actually actually going to implement a tree map over here. And why we are choosing tree map? Because tree map has
19:08:49
a property that it automatically sorts all the values based on its uh uh id or
19:08:55
key. So since we we already need that so we are we are good with that. Now in
19:09:02
terms of the second property for the stream map we will also have to see that how we are going to store these values.
19:09:09
Now these for for storing these values the important property we need is that
19:09:14
at any point we insert any value we will need to insert it in the right place and
19:09:20
we will need to maintain the decreasing order in this case. So in order to maintain the decreasing order the best
19:09:27
data structure to use this is to actually use a priority Q in this manner
19:09:32
and in the priority Q we are actually going to uh flip the basic condition
19:09:37
like originally in the priority Q whenever you stored the value all the value gets stored in an increasing order
19:09:43
but the thing is over here since we are using max heap we are going to need
19:09:48
decreasing order so that's why we are going to revert whatever the entry we have for this priority Q and this is how
19:09:56
we are going to use an additional data structure to solve this problem. So now if we calculate the time and space
19:10:01
complexity for time complexity essentially we are going to do bigo of n log n work in total because uh first we
19:10:11
will have to iterate over this input that takes n work then we will have to
19:10:16
create this tree map and fill in all the values. uh also we will have to maintain the priority q that takes n log n work
19:10:27
and uh in the end we will have to generate this answer. So this takes n work because we will have to iterate
19:10:33
over whatever this tree map is. So the biggest the longest work we are going to do is going to be n login and in terms
19:10:40
of space complexity we are creating this additional data structure to store all
19:10:46
the values. So that's why we are going to use uh big go of n uh as additional
19:10:52
space complexity. So if you see this this is also same as our sorted uh
19:10:57
approach like time complexity and space complexity are not different at all. But the thing is in this approach we are
19:11:04
actually doing things pretty smartly and as mentioned like suppose rather than in
19:11:10
this case we are given the problem for student and scores. Suppose we could have been given the problem of uh any
19:11:16
any particular player and uh their goal scoring average. So we need to calculate
19:11:21
something related to that or we could have given scenario where any company's stock performance over the last five
19:11:27
years and we need to select the top performing four quarters out of amongst those five years for all the companies
19:11:33
and we need to return them in a sorted manner. Like these are all the different ways where how this question can be
19:11:39
framed but we can actually use it and uh provide the answer using this max heap
19:11:46
concept. Also there is another way to solve this problem using min heap. Uh so
19:11:51
let me know in the comments if you want me to solve the min heap as well and I can I can also show you to show you that
19:11:57
approach. First of all, we are going to create our
19:12:03
tree map where uh in the key we are going to store the ID and uh as the
19:12:09
value we are going to store a priority Q.
19:12:16
We are going to name it scores.
19:12:26
Now we are going to iterate over the given input array and uh we are going to
19:12:33
store all the values to our tree map.
19:12:40
So the first value inside the given input array at the zero index is going to be id. So we are going to create a
19:12:47
new new variable called ID
19:12:54
and the second value is going to be score.
19:13:05
So first we are going to check that if the current ID already exist inside our hashmap or not and if it does not exist
19:13:12
we will add it there. And we are also going to initialize a
19:13:19
priority Q to manage the heap property
19:13:25
where we are going to store all the values in a decreasing manner and in by
19:13:31
default all the values in the in the priority Q are stored in an increasing manner. So this is the way to reverse
19:13:38
that order. I'm sure that different languages will
19:13:43
have different formatting but that is the general idea and once that happens we are going to update uh the value of
19:13:49
scores uh score for every single uh ID.
19:13:56
Okay. Now this uh hashmap should should have all the uh values stored and now we
19:14:01
simply have to iterate over it and generate our answer. So first we are going to create a list of integer where
19:14:09
we are going to store all the answers. Now we are going to iterate over the new
19:14:14
hashmap that we have created. For every single ID we are going to
19:14:20
calculate the value of sum. So initially we are going to have the value as zero and now we are going to uh iterate over
19:14:26
the first five elements inside the priority Q
19:14:32
and every single time we are going to increase the value of sum
19:14:43
and since this is a Q we are simply going to pull values every single time.
19:14:52
And once that is done, we can simply end uh we can simply store the results
19:14:58
inside our uh list that we had created. And for the sum, we are going to divide
19:15:04
it by five because we need to store the average.
19:15:10
Okay. So now we are done with all our calculation. Now we simply need to uh
19:15:15
create a two-dimensional array and store the value of whatever the uh answer we
19:15:21
have found and return that. So we are going to name it as answer array. And uh
19:15:31
now we will return the this newly created answer array.
19:15:44
And uh yeah this this should be our uh answer. Let's try to run this code.
19:15:51
Seems like our solution is working. Let's try submitting this problem. Okay, our submission works pretty fine
19:15:58
and uh I would be posting this code in the solution or in the comments. You can check it out from there. And
19:16:14
so the lead code problem we are going to solve is called k largest element in a stream. Now we can see that this one is
19:16:20
a lead code easy problem and also an extremely well-like problem on lead code. The problem statement is quite
19:16:25
straightforward. We need to design a class that where we can find kth largest
19:16:31
element inside a stream and we are told that we need to find the kth largest element in uh in terms of sorted order
19:16:38
number not the kth distinct element. This is just to avoid confusion. Now let's see the requirements for kth
19:16:44
largest class. Basically we need to implement two methods. First method is kth largest method where as an input we
19:16:51
are given an integer k and we are also given an integer array called nums. Now amongst these integer array nums we need
19:16:58
to return that whatever the k largest element is. So suppose the k given k is
19:17:03
equal to three we need to return that what is the third third largest element inside this array. Second one is an add
19:17:09
method where we are continuously adding value to a continuous stream and in that
19:17:15
continuous stream we are able to re represent or return the k largest
19:17:20
element in that continuous stream. So with every new value being added we can determine that this is the largest
19:17:26
element inside the current k array. So for both the case let's try to understand this with an example. Suppose
19:17:32
this is the array we are given as an input and we are being told that k is equal to 3. We need to find the largest
19:17:38
element. Okay. So logically we can see that over here the largest element is
19:17:43
seven. Second largest element is six and third largest element is five. So in this case we need to return five as the
19:17:50
answer that this is the largest element. Now say for the same example this we
19:17:55
took care of the k largest element method the first method. Now for the second method the add method. Basically
19:18:03
let's say that we are given K is equal to three. Okay. And this is a continuous stream. So first we add value number
19:18:08
one. Currently we don't have any large value. Then we add value number two. And then we add value number five. Now so
19:18:14
far what is the third largest value inside this continuous stream? So the answer is going to be one. Then we
19:18:21
decide to add value number four. So once again what is the third largest stream currently? So third largest value would
19:18:27
be value number two. So we will need to return two. Let's say we add value number uh three. So currently what is
19:18:33
the third largest stream? So in this case the third largest element so far amongst these five element is value
19:18:39
number three. So we need to return this. So basically in both the cases we need to find that for any particular given
19:18:46
input what is the kth largest element. Now for the for this uh add method you
19:18:52
would say that hey we need to check for for every single time. So how can we do do that? The idea would be to design a
19:18:59
data structure where at every given moment we should be able to quickly identify that hey currently by adding
19:19:06
this value to this particular data structure the kth largest value is going to be either one or two or three
19:19:13
depending on the number of elements that are currently present inside our existing stream. So let's try to see
19:19:19
that how we can actually uh solve this problem.
19:19:27
Okay. So if we see the brute force solution for this problem, brute force solution is actually quite straightforward. Let's say for given
19:19:33
input array, we can simply start iterating over every single value in order to find the maximum value we found
19:19:40
so far. Then we can repeat the same process to find the second maximum value and then we can find the third process
19:19:45
to find the third maximum value and that would basically yield us the result of let's say if we are given K is equal to
19:19:52
3. the uh this approach is very slow basically it yields in big of n square time complexity so we definitely don't
19:19:59
want to do that so that is one option
19:20:04
second option in this case is let's say that for the same given input if somehow
19:20:10
we decide that we can actually sort this given input then it becomes very easy for us to find any kth largest element
19:20:18
so let's say in this case the sorted array is going to look like just all the values from 1 to 7 and in this case the
19:20:27
kth largest element let's say our k is equal to three which means we need to pick the bottom third value uh in the
19:20:33
answer and we can simply return this one so the sorting solution would work fine but the thing is in order to create like
19:20:39
from this non-sorted array to sorted array it's going to take n log n time so but this is still a much bigger
19:20:46
improvement compared to our brute force approach and this is actually what we are going to take into account in order
19:20:52
to solve the problem. But the thing is not only we need to create like an add a
19:20:58
data structure where we can store the sorted value and find or calculate the result but for our add method because we
19:21:05
need to continuously check for any particular existing value that is being added into the stream that what the k
19:21:12
largest element is. So for every single time doing the sorting would not make much sense. rather with addition of
19:21:20
every single value we need to keep track of all the largest values that we
19:21:25
currently have so far and for that what I'm suggesting is that we actually use a very popular data structure called heap
19:21:32
that is specifically designed to store or identify k largest or k smallest element the approach I'm suggesting is
19:21:39
that for this particular heap we actually create a min heap of the size k
19:21:45
okay and what does min heap means is that it it stores the values in like the
19:21:51
minimum order in its sequence. So let's say currently in our array we have
19:21:56
values like two uh and four and then uh one something like this one. So this is
19:22:02
currently not sorted. But if we try to put those these values inside the min heap, it is going to store values as one
19:22:08
and then uh two and then four. So basically we will have sorted values
19:22:14
that are being stored and adding every single new value inside the min heap only takes logarithmic time. So log n
19:22:21
time. So the idea would be that if we just have a min heap of size K that is
19:22:27
number one scenario and number two condition is that whenever we find a value that is actually greater than the
19:22:35
current value we have then we are going to pop this value out and then whichever value x we found we are going to push
19:22:42
this value inside our uh array and this should allow us to find the k largest element very quickly. Let's try to see
19:22:49
the solution I'm suggesting in action and then it would make much more sense. So, so currently this is our given input
19:22:55
array. We are trying to find the third largest element. So, what I'm suggesting is to create a min heap of size three.
19:23:02
Okay. Currently this min heap is empty. Now we have value number four. So we simply add value number four. Then we
19:23:09
have value number five. So remember because this is a min heap if there is like the uh low value it needs to be at
19:23:15
the very beginning. Okay. So then we add value number five. Once again we have value number one. So currently value
19:23:21
number one is actually smaller than both four and five. So we will min heap automatically would readjust itself and
19:23:28
we would have values 1 4 and 5 stored in this manner once again. Okay. So now it
19:23:33
let's say if up until only this point we want to find out that what is the kth largest element all we need to do is
19:23:40
just simply check that what is the very first element present inside the min heap and that is going to be the kth
19:23:46
largest element. So not only this min heap is going to allow us to calculate the k largest element for given input
19:23:52
array, it can see subsequently applied in order to use for our add method as
19:23:58
well. And that's why this one data structure is going to solve both of
19:24:03
our problems. So now currently the k let me just put down the answer over here.
19:24:08
Okay, that currently the minimum value is one. So that we can find and this answer is for the add method and at the
19:24:16
same time we will find this answer over here for the k largest as a okay that
19:24:22
will come when we reach to the end of this given input. Now once again we have value number two. So currently two is
19:24:29
actually greater than the very first value inside our min heap which means two should be our should be in our min
19:24:35
heap and we are going to pop the smallest value inside the min heap. So now currently we have values 2, four and
19:24:40
five. Once again the answer is going to be two because this is the third largest element we found so far in this stream.
19:24:46
Next we have value number six. So the moment we want to add value number six which means uh two is definitely clearly
19:24:54
smaller than value number six which means six needs to be added. But with addition of six four and five also needs
19:25:00
to be readjusted. So now four five and six. So so far up until this point this
19:25:05
point the third largest element is going to be value number four. Okay once again now next element we need to add is value
19:25:12
number three but currently three is actually smaller than the current value we have inside the min heap which means
19:25:18
we don't need to do anything. We can just simply skip over three as it would not be part of the solution. Next is
19:25:23
value number seven. So for value number seven once again we will have to do the readjustment. So four would be kicked
19:25:29
out and five and six would be adjusted to have five 6 and 7. Currently our
19:25:34
inside the stream the value is going to be five and uh the answer is also going to be five that five is the third third
19:25:41
smallest ele third largest element inside the given array. So just by
19:25:46
simply using min heap of size k and then having the logic that if the value we
19:25:52
are trying to add if that value is actually greater than the current very first element inside the heap we will
19:25:58
need to kick this element out and insert this value inside the heap then this solution would work perfectly fine. If
19:26:04
we see time and space complexity in this case the time complexity is going to be big of n log n because for every single
19:26:11
element we will have to enter it into inside the heap. So that's why the time complexity is n login. If we see space
19:26:17
complexity, it is going to be bigo of k where k is the num the kth element we
19:26:23
are trying to find because we are initializing a new min heap of size k. And for those who don't know min heap
19:26:28
also means a priority cube. So that that's the logic right there.
19:26:38
So first of all we are going to initialize our priority Q and integer K a couple of private variables to store
19:26:43
them. Then we are going to have our K largest method where we are going to store the values of K and also inh
19:26:50
initiate a new min heap instance with the size K then we in for every single
19:26:57
element that is currently present inside the nums we will need to add that value uh inside our nums array. So for that
19:27:04
rather than doing anything else we can just simply use the add method. And now let's quickly also see the add method
19:27:10
where we first check that if the current minhub min heap size is less than k then
19:27:16
we are simply going to add the value inside the min heap. If that is not the case then we are going to check that if
19:27:24
the given current value is greater than the current very first or smallest value
19:27:29
we have inside the min heap then we will have to kick that value out and then we will have to add the new value we are
19:27:36
currently at inside the min heap. In the end we simply need to do a peak operation or the very first element that
19:27:42
is present inside the min heap and that is going to be the kth largest element for us and that's it basically. So now
19:27:49
let's try to run this code.
19:27:56
Okay, seems like our solution is working as expected. Let's submit this code.
19:28:01
And our code runs pretty fast compared to lot of other solutions which is pretty good. It is excellent in terms of
19:28:06
space complexity as well. And once again the coding solution is present on our GitHub repository. So you can go and
19:28:12
check it out from there. Thank you.
19:28:24
So now we are going to do one of my favorite problems on lead code that is called task scheduleuler. We can see
19:28:30
that this one is a medium problem and also a very well-like problem. Now I just have one request for you. I really
19:28:36
want you to pay utmost attention to this particular problem because if you can understand to solve this problem there
19:28:41
are lot of important lead code concepts that would enshrine in your brain. So
19:28:47
please please please pay at most attention. Now let's get started with the question. Uh basically we are given
19:28:53
an array of CPU tasks and each task is rep represented by a letter uh somewhere
19:29:00
between A to Z. Then we are also given a cooling time N. Now we are told that
19:29:06
each cycle or interval allows the completion of one task. Okay, that's
19:29:11
fine. And then we are told that task can be completed in any order. But there is
19:29:16
one small constraint regarding this interval n that we are given. And that
19:29:21
is that identical task must be separated by at least n intervals due to cooling
19:29:28
time. Okay. So let's try to understand what it just mentioned with some
19:29:34
examples and basically we need to return the minimum number of intervals required to complete all the task. So let's try
19:29:41
to understand this with an example. In this case we can see that we are given three task that we need to complete.
19:29:47
First task is A, second one is B and third one is once again A. We are also given the cooling down period of two.
19:29:54
Now how does this cooling down period affect the our task is that identical
19:29:59
task must be separated by n intervals. So let's assume that during the first
19:30:05
window we start to complete task A. Okay. So we got rid of this task. Once again we got rid of this task as well.
19:30:12
Task B. Now the thing is we only have one task remaining that we need to
19:30:17
complete. But if we try to complete task A over here and if we see the difference
19:30:23
between the in this interval and this interval then we can see see that the
19:30:29
difference is only going to be one but the thing is it has to be separated at least by two because that is what the
19:30:35
cooling period is because once again I'm repeating both A and A are identical
19:30:41
task. We are told that identical task must be separated by at least n
19:30:46
intervals. n in this case is two which means two identical task has to be separated by two intervals. Currently we
19:30:53
only have it separated by one interval. So we will actually have to add one more interval over here where we are not
19:30:59
going to do anything. So this would be an idle period where we are just going to stay idle just to complete that one
19:31:06
more interval. And now we have one and one two intervals completed. after we completed task A and then once again we
19:31:13
can complete the remaining task A. So totally we need to return the minimum number of intervals required to complete
19:31:20
all task and in this case we can see that we took 1 2 then this idle third
19:31:25
and then this completing a4. So in total we took four uh intervals to complete
19:31:31
this task. Let's try to understand this with couple of more examples. Next example is once again we are given n is
19:31:37
equal to two. Now in this case we have three identical task. We have three A's and one B. So one logical uh solution
19:31:43
would be we can start with task A. Once again we go to task B. Now we know that
19:31:48
the cooling period is two which means we cannot use a task A once again. We will have to stay idle. So we got rid of this
19:31:55
one. Okay. Now once again we can do task A. But after completing task A once
19:32:01
again the next task we need to do is once again task A for which we have to have two idle cycles. So since there are
19:32:08
no other tasks remaining we are going to remain ideal for two more cycles and
19:32:13
then we are going to complete task A. So if we calculate in this case we need in
19:32:18
total seven intervals to complete every single task in this input. And same way
19:32:24
in this approach we would actually need uh in total eight intervals. How?
19:32:29
Because we are given three A's and three B's. So logically we can do task A then we can do task B and then we cannot task
19:32:36
do task A or B once again. So we will do an idle scenario. Once again we would do A once again we would do B and once
19:32:43
again we would do idle and once again we would do A and once again we would do B and then we don't need to stay idle
19:32:48
because we completed all these six of the task. So that's what the problem is
19:32:54
asking us to solve. I know understanding this problem is quite tricky. Now first
19:32:59
let's try to understand the brute force approach.
19:33:04
Now logically the most simplest brute force approach would be to try out every single possible com permutations and
19:33:11
combinations. So we start with task A. Then once again we try to find that what is the next task that is not A. Once
19:33:18
again we identify task B. Once again we mark task B. Once again we try to identify that is there any other task
19:33:24
that we can do that is not A nor B in within this two window period we cannot
19:33:29
find anything. So then we decide to go idle once again we repeat the same process and once again we keep on
19:33:35
finding the next task. So this is a very slow approach and we are doing lot of
19:33:40
repeated work just to do this one because number one we are not sure that how many number of total tasks are
19:33:46
available. And number two, we are not sure that what is the frequency of every single task. So we cannot we cannot know
19:33:53
that during any particular interval cycle how many number of tasks we can accommodate. That is a one huge problem
19:34:00
with this brute force approach. And this problem is what we are going to solve
19:34:06
and exploit it in order to make this algorithm much much much faster. So let's try to understand that what is the
19:34:12
optimal solution I'm suggesting. But for optimal solution first we will have to build up some logical understanding on
19:34:21
how we can improve our solution. Okay.
19:34:27
So for that once again let's take our favorite example where we are given three A's and three B's and once again
19:34:34
we are given our n is equal to two. Logically most efficient matter for us
19:34:39
to solve this problem would be that in the in any particular given input first we need to find out that what is the
19:34:46
character that occurs most number of times and we always have to start with
19:34:52
that character in order to complete it in the fastest manner possible. So logically in this case both a and b
19:34:59
occurs three times. So what I'm suggesting is that first approach we can take first smart approach is that we can
19:35:08
actually take an entire uh input run it through some sort of like array or
19:35:14
hashmap and create a frequency map and in this frequency map we are going to make sure that every single time any
19:35:21
particular character how many times it appears that is number one thing. Next we will need to learn that what is the
19:35:27
maximum time any particular uh value repeats and then we will need to pro
19:35:33
store the values in the decreasing order. So once again we will need to find some way to sort this frequency
19:35:39
map. So for that one of the very good approach we can take is that we can actually create a heap where inside the
19:35:46
heap we can store the information that how many times any particular character appears and we can actually store its
19:35:52
information. So let me just make this slightly different and we are going to have B appear two times. Okay. So now it
19:35:58
makes sense that A is three times and B is two times. Okay. Now one more logic
19:36:04
I'm suggesting is that we actually take understanding of this scenario that what
19:36:10
is this N represents. So basically this n simply represents that how many number
19:36:16
of computations we can do back to back on separate characters during any
19:36:23
particular interval size. But the interval size has to be n + one. Why n +
19:36:29
one? Because remember we want let's assume let's go back to our very first
19:36:35
example. Now let's try to understand this logically. First let's say we add value number a. Okay. Then we add value
19:36:43
number B. Okay. Now how many more operations we can do where we can
19:36:51
basically either either there can be two options. Number one option is that maybe we have
19:36:58
some other value that is not A and not B that we can add over here. That is one
19:37:03
option. If that is not the case, another option is that instead of adding this another value, we will need to add an
19:37:09
idle value over here and then the whole cycle of once again reaching out to
19:37:15
character number A would reset because then we would have covered the two destination from this our original value
19:37:22
one a that we were looking at. Which means that in order depending on the
19:37:27
value of n we would actually have to consider the scenario of n + 1 as part
19:37:33
of one cycle because in one cycle we can only take unique characters during that
19:37:40
one cycle and if we have less unique characters than this one cycle then we
19:37:45
will have to use idle cases. So which means if we have unique characters we
19:37:50
can simply reduce the values of those unique characters. So in this case we got rid of this 1 A and then 1 B. So we
19:37:57
are basically reducing the values. Let's say if this one was C then we could have just reduced C but we don't have C. So
19:38:03
we still have A. So which means repeated characters would only be decreased by
19:38:08
one during one N +1 cycle. And if we have unique characters, we will try to
19:38:14
fit as many unique characters as we can inside this n plus1 cycle. So this is
19:38:19
the second improvement we are trying to do of applying n +1 uh cycles. So let's
19:38:25
understood that uh number one we already know that we created our hashmap uh sorry we created our frequency map then
19:38:32
we created a heap to store the frequencies that are coming in and next we are going to be marking the scenarios
19:38:40
based on n +1 cycles. Now these are the three improvements. Now I'm suggesting
19:38:45
fourth improvement and that's why I'm telling you that this problem is such a mind-blowing problem because you are
19:38:51
making improvements after improvements after improvements in order to make the efficient algorithm and that's why you
19:38:57
are learning lot of new things. So that's why I'm paying my my utmost attention coming back to the question.
19:39:03
So understand in this case that so far we are keen on understanding that how
19:39:08
many number of A's are present and how many number of B's are present and how many number of C's are present. The
19:39:14
thing is apart from storing this value inside the frequency map, we don't have
19:39:19
any other information that we need that we need to utilize this for. All we can
19:39:25
do is that we we are already tracking the values based on the cycles. We
19:39:31
already have a heap to store the values in sorted order. Now instead of storing
19:39:36
these characters we why don't we just store the frequencies because in the end we simply need to return that what are
19:39:42
the total number of intervals we are going to need. So in the heap we can actually store the frequencies. The idea
19:39:49
is we are going to be traveling in the cycle by manner. So cycle in this case is this is two. So there there is going
19:39:56
to be cycle of threes. Okay. And we know that how many number of unique characters are present inside this given
19:40:02
input because inside the heap we only have two distinct frequencies. So that's why there are only two unique characters
19:40:09
present. So this becomes our way to understanding that there are only two unique characters. We know that in one
19:40:14
cycle we can only iterate over just unique characters and reduce their
19:40:20
frequencies. For rest of the time we will have to put the idle slots. And what I'm suggesting is that we initially
19:40:27
start our heap this way. Then we are going to run in the cycles of threes.
19:40:32
With every single cycle, we are going to pop the elements out of the heap to make
19:40:37
sure that whether heap is empty or not. If he heap is empty, if there are no values inside the heap, then we will
19:40:43
simply add idle values uh till we make n plus one. So why don't we why do we even
19:40:49
make idle values? We know that after removing all the elements of the heap basically for this cycle we still have
19:40:56
some elements that for which we haven't calculated the frequency and if there
19:41:01
exists some frequency which means the entire n +1 has to be part of the answer
19:41:06
and then we simply have to reduce the frequency by one and once again repeat the same process. So this is the whole
19:41:14
solution I'm suggesting. Now let's me let me quickly show you the optimal approach. Let's walk through the optimal
19:41:19
approach and then we will see the coding solution.
19:41:25
So if we see the optimal approach now it is going to make much more sense. Once
19:41:30
again let's take our example and we have three A's and two B's and we have n is
19:41:37
equal to two. Okay. Uh logically we have our heap. So currently inside the heap we only have values three and two that
19:41:44
is the frequency map. And notice that this frequency map is actually sorted based on the uh ascending order
19:41:50
property. Then once again for n is equal to two which means we are going to do the cycles of value three. Okay. So
19:41:57
let's try to do the first cycle of value three. During the first cycle of value three we are going to pop one element
19:42:03
this three out of our heap. Currently we have and we are creating a temporary list to store the value of heap and then
19:42:10
we are going to reduce it out of the temporary loop. Okay. So currently this is three. We popped one element out.
19:42:17
Currently this is two. Once again we popped both the elements out. And we realize that currently our heap is
19:42:22
completely empty. There are no values inside the heap. So if heap is empty then we need to check that what was the
19:42:30
value that we took out from the temporary loop. We took out the values three and two which means we will have
19:42:36
to reduce these values and reducing these values are going to be 2 and 1 which means we the temporary list is not
19:42:43
zero. So in this case because temporary list is not zero and our heap is empty we know that during the first cycle we
19:42:50
will have to do three intervals. So we are going to mark three that we have completed so far. So we are going to
19:42:57
have a variable called interval where we are going to store the values. So we so far we have completed three variables.
19:43:03
Once again notice that inside the temporary list we first had values three and two but we reduce the frequency by
19:43:09
one. After reducing the frequency once again we are going to populate this value 2 and one once again back into the
19:43:15
heap. Once again we are going to run the operation. So once again in our temporary list we are going to have
19:43:21
values two and then value one coming in and we are also going to have a heap
19:43:26
becoming empty. Now heap is empty. We try to reduce the frequency. So reduced
19:43:31
frequency is going to be 1 and zero. Now after reducing the frequency we realize
19:43:37
that uh there are still some values present which means this entire interval we are also going to consider. So it is
19:43:43
going to be 3 + 3 so far. After this once again we realize that this value is zero. So zero value we kick out from the
19:43:49
temporary list. We put the value back inside the heap. So currently heap only contains value number one. Okay. So now
19:43:57
after containing value number one we will try to pop value number one out. Currently heap is empty but we we are
19:44:03
not going to add three so far because this might be the last character which is the case because in the temporary
19:44:08
list we identify that there is only one. If we do like a reduce operation minus minus then this becomes zero which means
19:44:14
temporary list does not have any value and heap only had one value. So we are simply going to add that value that we
19:44:22
take out from the heap or take out from the temporary list. So in this case we need to make minimum seven intervals to
19:44:28
complete each of these cases and let's try to walk through these seven intervals. So of course our given n is
19:44:35
equal to two. So first we are going to do operation a once again operation b and then we will have to do idle
19:44:40
operation. Once again we are going to do operation a operation b and our idle operation. So now so far we have taken
19:44:46
out two a's and two b's and in the end we simply have our operation a we need to do. So total we need to do seven
19:44:52
intervals in order to complete this problem. And this is the solution. I know I went over a lot of things but I
19:44:59
hope that this made sense that what I was explaining. If we see time and space complexity in this case well time
19:45:05
complexity contains lot of steps. So number one step is we need to build frequency map that takes big of end time
19:45:11
plus we will need to iterate. We will need to generate the heap. So that takes big of n login time. Then we will have
19:45:19
to run our while loop iteratively till we reach out till we complete every single cycle. That is once again going
19:45:26
to take bigo of n and then we will have to subsequently do the number of total
19:45:32
number of intervals that are that we are going to be able to make and that can in the worst case scenario it can be big of
19:45:38
n². So in total we can say that our time complexity is still going to be big of n
19:45:43
square but this is much more efficient approach comp compared to our brute force that would have yielded us big of
19:45:50
n cube of cube time complexity. So that that was going to be horrendous. If we see uh space complexity well we are
19:45:57
using frequency map and we are also using heap and plus temporary array list. So basically we are using we go of
19:46:03
n extra space and this is still in my opinion a good enough time and space complexity.
19:46:12
So here is the coding solution. First thing we are going to do is for given input task we are going to run across
19:46:18
and create a new frequency hashmap where we are going to store the frequency for every single task or every single
19:46:25
character. Once we have frequencies we are going to build our max heap based on the frequency. Uh so we are going to
19:46:31
initialize our priority Q to store the integer values of the frequency sizes
19:46:36
and we are going to add all of these values from our frequency map and they would automatically sort be sorted in
19:46:43
descending order. Next thing is we will need to process every single task. So
19:46:48
initially we are going to have our val variable time set up as zero. then we are going to have a condition that while
19:46:55
our given heap is not empty we will we will need to do the following. So first
19:47:01
thing is that we will need to initialize our temporary list that we mentioned that we will have to create. Then we are
19:47:07
going to run a for loop from i is equal to0 to i is less than n + 1 which means
19:47:14
this is going to be one of our cycles. So this is going to be our cycle logic
19:47:19
where we are simply checking that we are going to check if the max heap is not
19:47:25
empty. We are going to keep on pulling every single value out from the temporary list uh to the temporary array
19:47:32
list. And we will keep on repeatingly doing it until our given uh max heap is
19:47:38
either empty or we complete the n plus1 cycles. In either case we will have to
19:47:43
add n plus1 items uh depending on this then we will have to reduce the values
19:47:49
from the frequencies. So because we are popping values out from our temporary uh
19:47:55
from our heap which means currently they are stored inside our temporary array list. So we are going to reduce the
19:48:01
frequency and keep on checking that if the frequency is greater than zero we
19:48:06
are simply going to add that value to our max heap. If the value is equal to zero then we are not going to add it to
19:48:12
our max heap. Next thing is we will need to update the time and the time update is going to be quite straightforward
19:48:18
that if the given max heap is equal to empty then we simply need to update the
19:48:24
size by m n + one. If that is not the case, then we will need to update the
19:48:30
size or update the time based on the temporary variable size we had. Which means that was the
19:48:37
additional values we found inside our uh temporary array list that got popped out of heap. And in the end, we simply need
19:48:44
to return the time and this should provide us all the intervals we had. So this was a brilliant question, a
19:48:50
brilliant solution. Now let's try to run the code.
19:48:58
Okay, seems like our solution is working beautifully. Let's try to submit this code
19:49:04
and our code runs pretty fast in terms of time and space complexity. Once again, the coding solution is available
19:49:10
in our GitHub repository and the link of the GitHub repository is in the description. So, feel free to check it
19:49:15
out from there. Uh, thank you.
19:49:27
So the lead code problem we are going to solve now is called employee free time. Uh with this one is actually a lead code
19:49:33
premium problem and that's why you see that this interface looks different. This is actually defined as a lead code
19:49:39
hard problem but in my opinion this should have been a medium problem. But anyways let's try to focus on what the problem statement is. Basically we are
19:49:46
given a list of schedule of employees that represents the working time for
19:49:51
each of the employee. Now each employee has a list of nonover overlapping
19:49:56
intervals and these intervals are in sorted order order for each employee.
19:50:01
Okay. Now we need to return the list of finite intervals that represents common
19:50:07
positive length free time amongst every single employees in a sorted order. Now
19:50:13
in this list we can see that we are given the working times for three
19:50:18
different kind of kinds of employees. So this is the timing for employee one. This is the timing for employee 2 and
19:50:24
this is the timing for employee 3. If we plot all of these timings on one single
19:50:30
like uh linear line we can see that employee 1 works from 1 to two and then
19:50:35
works from 5 to 6. So amongst all of this time employee 1 is free. Same goes
19:50:41
for employee two. Uh employee two only works from 1 to three. So apart from this the entire period is empty for for
19:50:48
him or her. And this is the the list or the timing for employee 3. So we need to
19:50:53
find that what is the common free time amongst all of these employees. And we can clearly see that amongst this period
19:51:01
every single employees are free. So this three and four is the interval that is
19:51:07
common free time amongst all three employees. And this is what we need to return as part of the answer. So after
19:51:13
understanding that what problem statement is asking us to solve now let's try to realize that what is going
19:51:19
to be the common approach we can take to solve this problem.
19:51:25
First you see that for any particular employee this given intervals are in
19:51:30
sorted order that employee is working from 1 to two and then works from five to six. Same way over here we are though
19:51:37
we are just given one single data set but you get the idea that what I'm trying to refer but the thing is when we
19:51:44
actually have to find the common intervals for each one of these employees or each one of these timings
19:51:50
question is why are we even treating these as separate entities why don't we just consider that what if all of these
19:51:58
intervals are just a simple intervals on a on a string or on a time frame and
19:52:05
then we just need to find that what are the common spaces available between each one of them and that's the whole logic.
19:52:11
So the idea is that for some reason in order to do that we will actually have
19:52:17
to sort all of these timings that we are given for separate employees. Now
19:52:22
sorting these can be done like couple of ways. um either we can just simply use
19:52:27
like sorting function or we can create an additional data structure where we can inject all of these values one by
19:52:33
one and we make sure that we we try to sort them. So basically what I'm suggesting is that we use some sort of
19:52:40
of a heap or a priority Q. Now we know that the condition of a heap or priority
19:52:45
Q is that whatever value you enter it tries to sort it in some order. So we
19:52:50
will try to actually sort all of these numbers in the ending period. So whichever one has like the earlier
19:52:57
ending period would be sorted first and whichever has ending period later would be sorted later. If we try to do that
19:53:04
with this given input size then we would find some results that looks like this.
19:53:13
Now this is what our heap would have stored that these are all the intervals
19:53:18
we have and currently we see that these are not independent intervals. There are
19:53:23
there is lot of overlap also present amongst these intervals as well. But this gives us much clearer idea on what
19:53:31
we are trying to find. So now the logical step to do is that if we just
19:53:36
try to go and start finding out that what are the free slots then it would not work. Why? Because imagine over here
19:53:43
we see that this one uh ends at 1 and two and then this one ends at 1 and three. So we can infer that there is
19:53:50
some overlap overlap amongst these two. So we can deal with the overlap and we can say that combiningly like after
19:53:56
three we can try to find some potentially empty spaces. Now after three we identify that the for the next
19:54:01
slot starts at five. So this slot ends at three this slot starts at five. If that is the case we can clearly see that
19:54:08
hey uh this 3 to 5 slot is an empty slot. So we can use this one but this would not work. Why? Because for the
19:54:15
next one we can see that this actually starts at four. So the this 3 to 5 is
19:54:20
not a proper uh answer and we can find many false positives. So we before we
19:54:25
start finding out the empty slots we will have to do some work in between and that work is actually quite simple. All
19:54:32
we need to do is that every time we find an overlap we simply need to merge those
19:54:38
intervals. And how do we find overlap? Well, the answer is quite straightforward. If for one interval, if
19:54:44
the ending period ends before the starting period of the other one, we can define that there is an overlap between
19:54:51
those uh intervals. So, if we do identify the overlap, what we need to do is for the starting value, we need to
19:54:58
find the smaller value amongst both the intervals. For the ending value, we need to find that what is the larger value
19:55:04
amongst both the intervals. So if we repeat that that scenario in this case we can see that for this first scenario
19:55:12
this one ends at two and this one starts at one which means there has to be an uh overlap so we encounter an overlap. So
19:55:19
let's select the smaller value. So smaller value is going to be one because it's same for both but the ending period
19:55:25
is going to be three because three is the larger uh amongst both of them. So combining these two we can just say that
19:55:32
we only have one interval of size 1 and three. Same way this one is 5 six. Okay.
19:55:38
So currently this is three and this is five. So there is no overlap. So this is a separate entity. Now amongst this five
19:55:45
and six we need to check that whether this six and the next interval starts
19:55:51
after six or before six. So this one starts before six. So because this is this one starts before six. These two
19:55:57
also contain some some sort of overlap because there is an overlap. Once again for starting pointer we are going to
19:56:02
take the smaller value. So smaller value is going to be four. So we are going to put four as the starting of the new
19:56:09
interval. And for the ending point value we are going to use 10. So 10 is going to be the new ending interval. And
19:56:17
that's it. After after completely merging the uh all the overlapping
19:56:23
intervals we are only left with just two intervals. So this now we can very easily process that this one ends at
19:56:29
three, this one starts at four. So from 3 to 4 we have some empty slot that we can use. So that's quite simple and this
19:56:36
is what the whole solution is. So let's do a quick recap on what we just did.
19:56:42
First of all, we use a heap to basically uh sort every single interval inside
19:56:49
based on the ending uh order. So whichever was ending before would come
19:56:55
first inside the heap. Okay. Next we did the merge interval op operation for all
19:57:01
the overlapping intervals and also we did that in like normal fashion. We
19:57:06
simply need to iterate over the given uh values that are already sorted inside the heap. So that can very easily be
19:57:12
done. And after merging we only need to find the empty slots and put those empty
19:57:18
slots in some sort of answer array list that we have created. And that's it. This is simp simply we can return. Let's
19:57:25
try to calculate the time and space complexity. So in order to generate this process of sorting of every single
19:57:32
value, it takes n log n work. Okay. After we are done with this one, we need
19:57:38
to do the merge interval. So that takes big of n work. And after that we need to find the answer or empty slots that also
19:57:44
takes big of n work. So overall we can say that time complexity is going to be bigo of n log n which is quite good
19:57:51
given the input and this actually has practical applications as well. We see the application of this type of problem
19:57:57
in all sorts of calendar and google calendars and all the scheduling problems. So this is a real life
19:58:04
scenario that we are solving in uh lead code. And if we see space complexity well because we are using an additional
19:58:10
heap it's going to be big of n as well. So relatively this is good enough time and space complexity. Now let's quickly
19:58:16
see the coding solution for this one.
19:58:23
So first of all we are defining our class interval which contains the start and end value. Then we have our main
19:58:30
solution where we need to return the list of free times for every single employees based on the given schedule.
19:58:36
So first thing we are going to do is initialize a new array list to store the results. Then we are going to initialize
19:58:42
our heap or priority Q where inside the heap we are going to insert the values
19:58:47
based on the ending pointing. Uh so the value that ends first would be would be
19:58:53
placed at the beginning of the of our heap and then we are simply going to add all the intervals inside the heap one by
19:58:59
one irrespective of employees. After doing that our heap should contain all the values in the appropriate manner and
19:59:06
then we are simply going to run a while loop that while the given heap is not empty we are going to check that what is
19:59:12
the current heap and what is the current value and what is the previous value. We are going to check that if there exist
19:59:19
any particular overlap or not. If there is an overlap then we are we will have to select that what is going to be the
19:59:25
appropriate end pointer. If there is no overlap then we are simply going to add those values to our result array or
19:59:31
result array list that we have created and uh in the end we are simply going to update the next and previous counters uh
19:59:38
to update the values that we are fetching out of the heap and that's it basically. So this is the whole
19:59:43
solution. Now unfortunately I would not be able to run the solution because this is a lead code premium problem but
19:59:49
anyways the solution is available on our GitHub repository. So if you went you can go ahead and check it out from
19:59:54
there. Thank you.
20:00:05
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. So the
20:00:10
lead code problem we are going to solve today is called find medium from a data stream. is a very nice problem and if
20:00:17
you see some of the popular companies where I want to get a job who have already asked this question there are companies like Amazon, Apple, Uber,
20:00:23
Adobe, Bloomberg, Google, Spotify, Microsoft, Facebook, Nvidia, Bite Dance,
20:00:28
LinkedIn and bunch of more. So that's why I'm paying my art attention. I hope you also enjoy the video. So this is a
20:00:34
lead code hard problem and also very well-like problem. Basically we need to find the median from an incoming data
20:00:41
stream. Now in this problem uh basically we are being asked to implement the
20:00:46
median finder class. Now in this median finder class we need to implement these three methods where the first method is
20:00:52
the median finder method by itself. Second one is avoid add number which means that if with this method is being
20:00:59
called uh it will add an integer called nums from the data stream to our data structure. And third one is the find the
20:01:06
median that we need to basically find the median. Now let's come back to the problem statement. First we are given
20:01:12
the definition that what a median is. Median is the middle value in an ordered
20:01:17
integer list. Now this is the tricky part. We are being asked to find the
20:01:22
median from an ordered integer list. Which means that the input whatever the
20:01:27
input comes let's say the input comes like 11 3 5 something like that. We
20:01:32
still need to find the median as if the input was 3 5 and 11. So this is the
20:01:39
tricky part. like most of the people would not realize that the the wording ordered integer is there and then they
20:01:45
will get confused. So now we have get that uh sorted. Now we need to see that
20:01:50
what is the definition of the median is. Basically median is the middle value and if the size of list is even then which
20:01:58
means there is no middle value. In that case we need to find the median as the uh average of two middle values and we
20:02:06
are given some examples but we are going to see this in much broader examples. Um
20:02:11
so first let's try to understand this with some uh existing example. Suppose we are given a stream that looks like
20:02:18
this. 1 2 5 11 15 uh 16 something like
20:02:25
this. What would be the median in this case? Well, if we go based on the definition currently, well, this stream
20:02:31
is actually an even stream, which means that there is no exactly one middle value. Uh we are currently seeing two
20:02:38
middle values in this case. And also notice that for this whole thing, I actually set it in ordered motion
20:02:44
already. So we are going step by step. So first this is an ordered list uh that
20:02:50
is an even list and it has two middle values. So in this case the median is going to be the average of these two
20:02:56
values. So which turns out to be 5 + 11 uh 16 divided by 2. So the answer is
20:03:02
going to be 8 in this case. U so second again um let's suppose that once again
20:03:08
the list is ordered list. So 1 2 5 8 and 9. In this case we are given we are
20:03:14
dealing with odd numbers. Now for these odd numbers the middle value is quite obviously clear and that is going to be
20:03:21
value number five. And again the ordered property is still maintained in this example as well. So in this case the
20:03:27
answer is going to be simply value number five. Uh now let's take one notch
20:03:33
a little bit more complicated. What would be the median in this case? Uh since this is odd number we know that we
20:03:39
need to find the middle value. But in this case this is not in order. So first
20:03:45
we will have to put this in order. So that is going to be 1 3 5 8 and 15. And
20:03:51
in this case now since it is easy to calculate the middle value it is going to be five. So this would be another
20:03:57
scenario. Now with these examples you at least got one broader idea that how to
20:04:03
deal with the median finder class like uh when we need where we need to first
20:04:09
of all uh create a method to find the medium uh second we need to create a method to add the medium and third we
20:04:16
need uh an object of this medium finder class. So basically we need to focus on these two items the most. Now the most
20:04:24
important part in this one is uh first we will have to see that what would be
20:04:29
the actual problem is going to look like. So actual problem is going to look something like this where there can be
20:04:36
multiple uh options. So first let's say that it selects and uh the option is
20:04:41
that you need to find uh the median but currently if we see our list uh or our
20:04:48
input data stream let's just mark this as input data stream. Currently in our input data stream there are no values
20:04:54
which means if we call out this find median function basically it is going to return zero. So this this time or return
20:05:00
null value actually not zero. So let's say that this returns the value null.
20:05:06
Okay. Now again we we are calling add number method. Uh so if we call add
20:05:13
number method and we we say that okay add number five. So in this case currently in our data stream there is
20:05:19
only one value that is five. Now we call add me u I add number method again and
20:05:24
we add value number six. So now our data stream has value number six. Once again we call the add number method and we add
20:05:32
value number uh two. So in this case currently our data stream has value number two. And then if we call the find
20:05:40
median method which means we will have to find the median. Now in this case ideally this find median method should
20:05:46
give us the answer according to all of these examples we saw. So basically first for this uh data stream it's 5 6
20:05:54
2. So we are going to put it in the ordered list that is going to be true five and six and the answer in this case
20:06:00
uh needs to be returned as value number five. So five is what we would return over here for the find median. Now again
20:06:07
there can be bunch of more uh operations to be performed same way. So let's say
20:06:13
that again we add a number uh and this case this time we add the number 11. So
20:06:18
our data stream is going to a value number 11. Now if you want to find the median then again there would be an
20:06:25
additional bit of uh changes. So it would be like this would be our sorted
20:06:30
data data stream and the median is going to be 5.5 and this is what we will return. So basically it will keep on
20:06:37
changing. Now our job is to do this in the most efficient manner. Okay.
20:06:44
Now in this array list what we are going to do is from whenever our main method
20:06:49
whenever we see add number method being called we are going to simply push one
20:06:54
number down this data structure. So let's say we got numbers coming in as 6
20:07:00
8 2 1 5. Okay this is the sequence of numbers that came in and then we
20:07:06
encountered the find median method. Now again since this is a brute force approach we are going to take this step
20:07:12
by step in the very preliminary fashion. So first thing that we would do is that we need to find the median of this array
20:07:19
list. But currently this array list is not sorted. So because this is not sorted we are going to simply sort this.
20:07:26
Now sorting an array or array list actually there are a bunch of different ways. uh but typically this can be
20:07:33
achieved in n log n time if we use something like quick sort or merge sort
20:07:39
but we are not even going to bother implementing those quicks sort or merge sort what we are simply going to do is
20:07:44
call collection dots sort method so if we call collections dots sort method in any programming language basically it
20:07:51
sorts the given array for us uh in n login time so after that we are going to
20:07:57
have a sorted array and the sorted array is going to look something like this uh
20:08:02
it's going to be 1 2 5 6 8 and this sorted portion took us n log n time.
20:08:10
Okay. Now for this one two uh now finding the median it becomes quite
20:08:16
simple because we know that for array fetching takes big of one time and also
20:08:22
putting the value takes big of one time. We already know the size of the array. So in this case the uh the array size is
20:08:28
going to be five. So because array size is five we know this is odd number and since this is odd number we need to find
20:08:35
the middle value. So middle value has to be located at position number uh three
20:08:40
or if we see in the array it has to be sorted array and uh the index value has
20:08:47
to be two. So because this is 0 1 and two and whatever the value is located
20:08:52
over here we are going to simply return that and that is going to be our answer. So let's break down uh how does our
20:08:58
brute force solution compare to everything we have done uh so far. So it
20:09:03
actually seems to do justification because if we see in this case the
20:09:09
finding median uh is being done through two processes. First process is that we
20:09:14
are sorting the given input and uh second process is that we are actually finding the median by doing the average
20:09:21
depending on the odd or even value. Now this case is a constant operation. So this can be done in big of one time but
20:09:27
the sorting is actually a little bit tricky and this takes n log n time. So
20:09:33
overall the finding median is going to be done in n log n time and uh adding
20:09:39
number adding number is actually quite quick. So that that is being done in big of one time. So if we see the total time
20:09:46
complexity in this case, the total time complexity for this brute force approach can be considered as uh n log n and that
20:09:54
is not so bad but we want to do it in much faster manner. Uh so we we will
20:10:00
have to strive for something uh that where we can store or where we can save in in terms of time complexity.
20:10:08
Well, optimal solution uh is actually comprised of couple of different
20:10:13
components and what those components are. First, we will have to find the room that where we can actually save in
20:10:20
terms of time complexity. So, we are currently taking care of finding median
20:10:26
by using first sorting the given input and second one is finding the actual median. Now, this portion is quite easy.
20:10:32
So, we can ignore this one. Uh this portion is the trickiest and why this is the trickiest because uh we actually
20:10:39
have an incoming data stream uh that is generating bunch of different random
20:10:45
numbers and we are taking these random numbers and creating them in a beautiful
20:10:51
sorted list and this sorted list is then being used to find the median depending
20:10:56
on the middle values. Now since we already know that the input that is
20:11:02
coming in is coming in at one at a time. So if the input is already coming at one
20:11:08
at a time, why can't we design a structure that automatically sorts
20:11:14
itself and we are not going to need to care about the sorting property. So we
20:11:19
already took care of one portion of it. And what would be that automated sorting
20:11:24
mechanism data structure is? Well, you already know it. It is actually called a heap or a priority queue where depending
20:11:33
on the how you configure it or how you set up, you can actually configure it to have in uh either in increasing order or
20:11:40
decreasing order. So no matter the sequence of numbers that are coming in at random, eventually this is always
20:11:47
going to be in the sorted manner. So if it is always going to be in a sorted manner then it becomes very easy for us
20:11:53
to basically find the median because we already know that how to find the median from a sorted property. Now uh there are
20:12:01
a couple of tricky parts over here and first let's break those down. Uh currently we have already decided
20:12:07
decided that we are going to use heap. Now what are the trade-offs with heap? Well, the first trade-off is that if we
20:12:13
want to insert any data, basically the insertion takes bigo of log end time,
20:12:19
right? Uh so that is adjustable because it is maintaining the sorting property.
20:12:25
So how it does it is that let's say that you have this initial heap that is being created and currently this heap is
20:12:32
empty. Now you have this one uh incoming value 15 coming in. So 15 comes in. So
20:12:37
it currently because there are no values it puts 15 as it is. Now let's say that
20:12:42
there is one more value coming in and that is value number 16. So now for this value number 16 heap is not just going
20:12:49
to append it uh anywhere in the um in the in the sequence. It is going to see
20:12:54
that okay uh let's assume that this is actually a min heap which mean which means that the topmost value has to be
20:13:01
the minimum value and all the other values would be greater than that. So in our min heap basically uh we need to
20:13:08
make sure that the first value remains the smallest and everything is sorted in uh increasing order. So in this case
20:13:15
because of this is a min heap it is going to put 16 over here and 16 is going to stored over here. Now suppose
20:13:23
we have another value coming in and that is value number five. Now this value number five is actually lesser than 16
20:13:29
and 15 both. So in this case it is actually going to find a proper bucket
20:13:34
or a proper place for five to be stored and that is uh that it is going to do
20:13:39
using the binary search and we all know that binary search takes login time. So that is why first it is going to do the
20:13:46
binary search to calculate that where to put this five. It calculates that okay currently the five is the lowest or the
20:13:52
minimum value. So that is why it is going to put five at the beginning and it is going to take care of all the
20:13:58
other values. So basically our heap is going to look like 5, 15 and 16. And
20:14:03
because of this property there is this login time penalty that we have to pay.
20:14:08
But this login is actually much better than n login because we are only doing
20:14:13
it once. So that is the trade-off. Now I hope I was able to explain you that how
20:14:18
does a heap work. Uh once we have that sorted now let's see that uh will this
20:14:25
make any improvement to our problem? Well, of course, it is going to make significant improvements to a problem.
20:14:31
Uh, currently, let's say that let's assume we are using a min heap. Uh, again, using the same example, let's say
20:14:36
that we have our data stream. Now, in our data stream, assume that we have all the values coming in uh at random. So,
20:14:43
the random values that are coming in at the moment are going to be let's say 1
20:14:49
15 3 9 11 13. Okay, this these are the random
20:14:55
value scheming. But we have a heap and we have a min heap which means it is going to take care of all the values in
20:15:01
the sorted manner. So sorted manner is going to be now in this case since we have seven digits or seven values stored
20:15:08
inside our heap which means that this is odd number. So because this is odd number we need to find the middle middle
20:15:14
value. Now this is the tricky part. We know that with array uh it was actually
20:15:21
easy to fetch any value from the middle because we were able to do it in big one time constant time. But that is not the
20:15:28
case with the heap. Uh so fetching the middle value it is actually going to take big of n divided by two time
20:15:34
because we are doing it sequentially one by one to reach to the middle middle point. So in that case since it is
20:15:42
taking that much time can we do some improvements to actually find the median
20:15:47
quicker. So now we know that what is the issue with the typical ordered list. Basically inside the ordered list
20:15:53
despite having all the values properly set up using the heap it will still take us time to reach to the middle pointer
20:16:00
and we want to basically make this process much faster. So how do we do that? Well, one simple conclusion is
20:16:08
that breaking this heap into two portions. And how do we break this heap
20:16:13
into two portions is that first we are going to have a max heap. Now what does
20:16:19
a max heap means? Max heap is going to be this portion of the given existing
20:16:25
list. uh and if you notice one property in this portion is that every single
20:16:31
element at the end of this heap is always going to be the maximum value compared to all of its peers and this is
20:16:39
the only value we care. Same way we would have another partition being made
20:16:44
inside our heap and that is going to be this remaining portion. Now inside this remaining portion we can actually call
20:16:51
this min heap. And why we are calling it min heap? Because the only value that is
20:16:57
of concern to us is this middle pointer. We don't care about all of these values. We only care about this value because
20:17:04
this is going to be the minimum value compared to all of its peers. And if for
20:17:10
an example if the current heap size or if let's say that max heap and min heap
20:17:17
we will try to make make them exact equal in terms of the number of elements
20:17:23
that are currently present. So let's say that uh in our current data stream if the values are even basically in that
20:17:31
case max heap and min heap they are going to have even values and in our data stream if the values are odd then
20:17:39
uh in our case our max heap is going to have one more value compared to our min
20:17:44
heap and that's it. So if the values are even or if min heap and max heap are
20:17:51
same in the size then uh the median value is going to be the combination of
20:17:56
or the average of this max and min heap. Uh and if it is odd basically we simply
20:18:02
need to return this max heap value or the max element. Confused? Don't be. Let
20:18:07
me get let me show it to you with an example. Suppose uh this is our current order current data stream. What would be
20:18:14
the ordered list? First, let's just try to understand. So, median in this case again that is quite easy to find. The
20:18:22
median is going to be this value number three. That is the middle value. And why we came up with this value number three?
20:18:27
Because once again uh this is the the total number of elements are in the odd
20:18:32
number. So that is why it is easy to find the median. Now let's see that how would my approach work. So first let me
20:18:38
quickly create a max heap and a min heap. uh so I'm just first giving you
20:18:44
the end result that how they are going to look like and then we will go step by step on how to implement that okay so
20:18:51
end result is going to be that this max heap is going to have all the values that are greater than the very first
20:18:59
element inside the max heap so max heap is going to look something like this uh 3 2 and 1 actually it's going to be 1 2
20:19:07
3 but I'm giving you more general idea so that the you visually it is more interesting that the very first element
20:19:13
is the element that we are looking for. So in this case this is going to be that and if we see it with the original list
20:19:20
basically we are taking care of these first three values. Same goes with the min heap what is what are going to be
20:19:26
the values? So the values are going to be simply four and five. Why? Because
20:19:32
the very first element is going to be the minimum value compared to all the other values. Now again going back to
20:19:38
our equation of the values being equal or one value being higher than the
20:19:43
other. So in this case currently if we see the number of values in our okay this mh is not the best abbreviation in
20:19:51
our max heap. Okay max heap and min heap. So currently in our max heap the number of elements are three. In our min
20:19:57
heap the number of elements are two because max heap has one greater element
20:20:03
the whatever the value of max heap is or the whatever the value of the very first character in the max heap is is going to
20:20:10
be our median and in this case if we were to ask the find the median we can
20:20:15
simply return the answer as three. Now let's see that how step by step we are going to maintain this property. So
20:20:21
first we have our max heap and then we also have our min heap. Now the property
20:20:28
inside the max heap is that the very first value has to be the biggest value compared to all the other values. Uh and
20:20:35
the min heap is that the very first value is going to be the smallest value. And also there are one more property
20:20:41
that every single value inside the max heap is always going to be less than or
20:20:46
equal to the min heap. Nothing more than that. So first we are going to enter enter the value inside the max heap and
20:20:53
that is this very very first value 15 52. So first we add 52 over here. Uh
20:20:58
currently min heap does not have anything. We took care of this value. Now the second value is value number
20:21:03
two. First we are going to check the size difference between max heap and min heap. And what the side size difference
20:21:11
is going to tell us is that whether the value should be added to max heap or min
20:21:16
heap. So if we were to add this value number two to max heap then the size difference between max heap and min heap
20:21:24
is going to be value two. So because this is greater than one we cannot have
20:21:29
them which means we will have to push one value to the min heap. But the question is which value and that is the
20:21:36
interesting part. So we know the property that every single value in the min heap has to be greater than max heap
20:21:44
because of this one. Uh so if we enter value number two in the min heap will it make sense? No absolutely not. Which
20:21:51
means first we will have to push the maximum value that is currently present
20:21:57
inside our m max heap to the min heap. So the first we are going to have value
20:22:03
number 52 being pushed over here and then we are going to have this value number two being pushed to our max heap.
20:22:10
Uh I hope this makes sense. uh if not try to re-watch the video for this portion and you will understand what I
20:22:16
exactly said. So now we already took care of value number two as well. And also remember because we have both the
20:22:23
values at the same time. If we want to find the median it becomes quite easy. We can do it in just constant time at
20:22:30
any given moment because let's say I tell you that after these two values there is a find median uh uh command.
20:22:37
You can do it quite easily. You can just say that okay 52 + 2 54 54 divided by 2
20:22:43
I think it's going to be 27 and 27 is the answer you can find it quite obviously so that is why this approach
20:22:50
is very fast now again going back to our example now this value number three we need to push in uh currently both of the
20:22:57
min heap and max heap the sizes are same which means the value has to be entered into the max heap because max heap can
20:23:04
have one more value than the min heap. So three we know we have to put push it
20:23:09
into the max heap. Now what is the property of the max heap? That very first element in the max heap has to be
20:23:15
the greatest element or the biggest element compared to all the other values. So in this case because two is
20:23:21
the small animal element. We are going to adjust our max heap. So first element
20:23:26
is going to be three and second element is going to be two. Now we took care of this value number three as well. Uh now
20:23:32
we have this value number five to take care of. Again five has to be added to the min heap. So if we should we add
20:23:40
five directly to the min heap or should we compare add it to the max heap? We
20:23:45
are going to check the very first or the biggest element inside the max heap. The
20:23:50
biggest element of the max heap is lesser than the value of the that we are trying to enter. Which means five can
20:23:57
easily enter our min heap. So since we are entering five into the min heap, we
20:24:02
also wants to maintain a property inside the min heap that the very first element inside the min heap is always going to
20:24:08
be smaller. Which means 52 we will have to move on the side and value number five we will have to put together
20:24:15
because up until this point even if you see that what are the elements? So the original elements were 52 2 3 and five.
20:24:23
If we just want to put them in a single ordered list, the value is going to look like 2 3 5 and 52. And we are only
20:24:30
concerned with these two values 3 and 5. And which we are able to make sure or use using this min heap and max heap. So
20:24:37
that's why we are going to get rid of all of this. Uh this was just for explanation purposes but you get the
20:24:44
idea that what we are trying to do. Now again once again we have the value number uh 11 that we are trying to
20:24:51
enter. So for this value number 11, it has to go to the max heap. What is the
20:24:56
property of the max heap? That the very first value has to be the biggest value. So currently the value is three. So
20:25:02
because three is smaller, so 11 will go over here in the middle uh in the very
20:25:08
first value. So we are going to get rid of these two and the value is
20:25:13
going to be 11 3 and 2. And currently what is the what is going to be the median value? Median value is going to
20:25:20
be value number 11 the biggest value of our max heap.
20:25:25
But question is can 11 stay there? Of course not. Why not? Because
20:25:32
every single element inside the max heap has to be smaller than every single element in the min heap. And currently
20:25:39
we have value number five that is actually smaller that is residing in the min heap. So that should not happen. So
20:25:47
once again we will have to first before adding 11 over here first we will have to add value number five over here and
20:25:54
then uh since the size differences between max heap and min heap is greater than one. So 11 would rather going there
20:26:02
it would enter over here and in this case uh the values are going to look
20:26:07
like that uh 11 and 52. Okay. Now we
20:26:13
have the very final element seven that we need to enter. So where should seven go? Again uh this already has one
20:26:21
element greater. So we know for sure that seven has to go to min heap. But uh
20:26:26
seven we we are going to compare seven with the very first element. So five uh seven is greater than five which means
20:26:32
seven can easily go into our min heap. And uh since seven is the smallest element we will have to make adjustments
20:26:38
before we enter seven over here. So the values are going to be 7 11 and 52. So
20:26:45
in the end we are going to have our two min heap and max heap. So max he max heap is going to look like 5 3 and 2 and
20:26:52
the min heap is going to look like 7 11 and 52. And now if we are being asked to
20:26:59
calculate the median it is quite obvious. We are just going to do addition of 7 + 5. So our value is going
20:27:04
to be 12 divided by 2 and the answer is going to be six. And this is the beauty
20:27:09
of heap and this is why this problem is a hard problem but also very popular problem. Uh let's calculate the time and
20:27:16
space complexity. So again for the time complexity uh first we need to find that
20:27:22
for the max heap and min heap. So insertion takes login time and
20:27:27
essentially we are going to be inserting values in the min max heap min heap
20:27:33
sometimes from max heap to min heap and sometimes from min heap to max heap. But in either case we are going to be
20:27:39
achieving that in login time. So essentially we are doing login four times and then for the one time we also
20:27:45
have to enter the value from the data stream to one of the heap. So essentially we are actually doing the
20:27:50
login operation five times. So if you want to be very specific you can mention five log n to be the uh exact uh time
20:27:58
complexity and plus in order to find the median this operation is actually constant. So go that is being done in
20:28:05
big of one time. So this is a very good time complexity. Now let's calculate the space complexity. So space complexity is
20:28:12
basically going to be big of n where n is the number of values that are currently present inside the incoming
20:28:18
data stream. So here is the coding solution. Uh first of all we are creating our class called median finder
20:28:25
where we have our two priority set. uh first one is a priority Q named low that is our max heap and second one is one is
20:28:32
our min heap. Now uh we need to create a method to add number. Basically to add
20:28:38
number we are first of all adding it to the max heap. Then we are balancing the both the heaps and then we are checking
20:28:45
that uh if they both are maintaining the proper sizes or not. uh if not we would
20:28:50
pop the element uh and move it to the other heap and in the end it becomes quite easy to find the median and that
20:28:57
is essentially you just uh check the size. If the sizes are equal then you do
20:29:03
the average of both the lowest and the highest value and divide it by two otherwise you take the value from the
20:29:09
max heap and return it as the answer. Uh so let's try to run this code. Okay,
20:29:15
seems like our solution is working as expected. Let's submit this code. and our code runs decently efficiently
20:29:21
and uh I would be posting this solution in my GitHub. So this is my GitHub repository and you can find bunch of
20:29:28
different solutions over here and it would it is going to be quite useful. Uh good luck.
20:29:39
So now the problem I'm going to solve can be asked in three different ways in three different interviews. It can be a
20:29:46
data structure and algorithm type of lead code problem. It can be a system design problem. And it can also be asked
20:29:52
in low-level design problem. So I'm going to do my best to explain in as much detail as possible. I hope you pay
20:29:59
utmost attention to this particular problem.
20:30:05
So the problem we are going to solve is called design Twitter and we all know what Twitter is. This one is a lead code
20:30:12
medium problem and also a very well-liked problem. Let's try to understand the problem statement. Basically, we need to design a
20:30:18
simplified version of Twitter where users can post tweets, follow and
20:30:23
unfollow other users and it is able to see the 10 most recent tweets in the
20:30:29
user's news feed. So the Twitter class we need to create should we should be able to initi initialize the Twitter
20:30:35
object. Then we need to create these four methods. First method is post tweets where we are providing in the
20:30:42
user id and tweet id that composes a new tweet with a new tweet id uh by the
20:30:48
user. Then we need to create a link list type of structure for get news feed
20:30:53
where depending on the user id we provide it retrieves the 10 most recent tweet ids in the user's news feed. Now
20:31:01
for this uh uh 10 most recent tweet ids we are given some logic that each item
20:31:06
in the news feed must be posted by the users who the user followed by the users
20:31:13
themselves. Okay. So you can you should only be able to see the tweets that of
20:31:18
the people that you are currently following. That's basically what it's trying to say. And this is the important
20:31:24
part that the tweets must be ordered from the most recent to the least recent. the latest one should come in
20:31:31
first in your feed. So you need to maintain that timely order. And then we are being asked to create two simple
20:31:36
methods that is follow and unfollow where you provide the ids of follower and follow E. And basically follower
20:31:44
should stop should start following with the follow method and they should stop following with the unfollow method. So
20:31:51
let's try to think and document all the things that we need to create. Okay,
20:31:56
number one thing is we need to create a Twitter class. Now in this particular Twitter class, we need to progenerate
20:32:02
four methods. Now logically first let's start thinking about each one of them
20:32:07
one by one. So let's take the small problems first because if you can't uh
20:32:12
solve the hard part, solve the easy part first. Now for the following and unfollowing logic, basically we have two
20:32:19
sets of users. So let's say that I am currently a user. Okay. Now I am as a
20:32:25
user my name is parth and that's it. Now there are bunch of different users just like me that I'm currently following and
20:32:33
they also have their own white buckets of being users and they might also
20:32:39
follow me back some might do some might some might not and they may also be following bunch of different more users
20:32:45
as well. So one logical conclusion would be that we wants to make sure that the moment for we I provide you that any
20:32:53
particular user uh let's say path and then I provide another user let's say uh
20:32:58
John Cena so I should be able to see immediately that whether path follows
20:33:04
John Cena or not and I would like to do this in the quickest manner possible. So the only way to do that is that if for
20:33:11
any particular user I create some sort of hashing solution like a hash set or a
20:33:17
hashmap where I provide the information of every single user that this
20:33:22
particular user path is currently following. And in this hashet then it becomes very easy for me to find that
20:33:29
whether any particular uh user ID is being followed by this user uh username
20:33:35
path. If that is the case, then I can quickly add and remove those entries. So that way I should be able to tackle both
20:33:42
follow and unfollow methods because then it becomes pretty simple for us to
20:33:48
identify that. But in order to accomplish that we will have to first take in few accounts or few
20:33:53
considerations. Number one thing is how we are going to configure our user uh
20:33:59
details like what are the items we should be putting in inside the user class. uh and for each user because we
20:34:06
are trying to create like a separate hash set. So how should that work? So we also have to think about that we are
20:34:13
trying to fix it using the users and for every single user having a hash set of
20:34:20
all the people that that particular user follows. So for that what I'm suggesting
20:34:25
is that we first of all create a separate user class and in this particular user class that number one we
20:34:32
have the user ID and then we also provide two methods. First one is a
20:34:38
follow method and second one is an unfollow method where both both the
20:34:43
things this follow and unfollow method does is exactly to look up inside the hashet for that particular user and
20:34:50
identify that whether there is a connection or not. In order to do that, we also need to have a hash set where we
20:34:56
are going to store the values of all the users that are currently that currently
20:35:03
this user is following. That's it. So this is what our user uh class should
20:35:10
look like because we are taking care of the ids and we are also taking care of follow and unfollow method. Now after
20:35:17
tackling the issue of follow and unfollow we need to also understand the logic of post tweets and get news feed.
20:35:24
So now the next lesser complicated portion is post tweets. So now once
20:35:30
again now let me deviate slight bit of side from the uh users and also go into
20:35:37
the issue of Twitter or tweets. So what for any particular tweet what are the
20:35:43
different items a tweet needs? So number one thing a tweet has to consider is basically what you are trying to tweet
20:35:50
right of course. So in this case we are we are being told that we are just posting an integer associated with that
20:35:56
tweet. So basically a tweet ID we are only post we are only going to be posting the tweet ID on what information
20:36:03
is there and that is sufficient. Okay. So every single tweet is going to have a tweet ID that we have to take care of.
20:36:10
Next thing is uh remember when we are trying to generate the news feed we need
20:36:15
to provide the top 10 most recent news or most recent tweets. In order to do
20:36:21
that we we have to identify that for these top 10 news feeds based on the
20:36:26
time we need to have some way to keep track of the time stamp that this tweet has been tweeted. So for any particular
20:36:33
tweet we will also have to keep track of the time stamp that at what uh time did
20:36:39
we created that tweet that is number second thing we have to identify. Third thing is we have to associate that what
20:36:46
what was the user who created this tweet. So in order to do that we can actually have the tweet ID or we can
20:36:55
have a post method basically on the user class where we can simply create a tweet
20:37:03
and this post method should follow should call this tweet method or this
20:37:08
tweet class where we are simply providing all the information we have uh
20:37:13
in order to create a new tweet and that's it. So now this tweet also has an
20:37:18
access to the user ID and this user ID and the tweet ID becomes our connection points to separate the tweets depending
20:37:26
on per user basis because remember when we get to the level of generating the news feed we will have to generate the
20:37:32
news feed based on the people I'm currently following who have tweeted. So I need the information of the user and I
20:37:39
also need the information of the tweet and I also need the information of time. So combination of these three attributes
20:37:45
should take it take place into my tweet class as well. And next thing is for for
20:37:52
our tweet uh typically tweets are generally stored in like a link list
20:37:58
sort of fashion because even for the generate news feed we we have to create the link list. So the ideal scenario is
20:38:06
that even for any particular user that is currently uh generating a tweet, we
20:38:12
also provide a link to call to the next tweet that this user also has made. So
20:38:17
when we get to the coding portion, this thing would make much more sense on how we are configuration this configurating
20:38:24
this user account and this tweet account. Now let me come back. Okay, now
20:38:30
uh and also let me do a quick recap. So far we have created the users class and
20:38:35
we have also created a tweet class. Uh in the users class we are storing all the necessary information that we need
20:38:41
for the user. So things like user ID and then things like uh tweet that the this
20:38:47
user makes and then what the hashet to store the information of all the people
20:38:52
that this particular user is currently following. We also have the tweet table where in the tweet we have the tweet ID.
20:38:59
We also have the user ID because we need to know that for any particular tweet
20:39:04
what user was associated with that and anyways we are also having a post method that deals with the tweet uh tweet class
20:39:12
we have on our site remember there needs to be there needs to be a connection in this case. Okay. So that's why need it
20:39:18
needs to make sense. Once again coming back for our tweet class and also uh
20:39:24
this is also going to be a time bound event. So we are also going to store time for each one of this one. Now
20:39:30
coming back to our main Twitter class. Okay, we already took care of follow and
20:39:35
we already took care of unfollow methods. We also took care of uh how how
20:39:40
we are going to post tweet method. So basically if we see the structure of the post tweet method in the original
20:39:47
question description, we are simply providing the user ID and we are also providing the tweet ID that this
20:39:53
particular user is posting. Same thing we what we can do is even for our post
20:39:58
tweet method we can simply uh provide in the values of the tweet ID
20:40:04
and the user ID and we can now we can associate all of these things together.
20:40:10
Now comes the tricky part and the tricky part is that uh last thing is we need to
20:40:16
be able to generate the news feed. Okay. So in order to generate the news feed
20:40:21
what we will have to do. So let's first try to understand logically what is being asked us to solve. We need to
20:40:28
provide the top 10 or the most recent 10 tweets that were being made by all the
20:40:35
people who I currently follow. Okay. So all the people who are followed by me.
20:40:42
Okay. Now this makes sense. Now let's try to
20:40:47
visualize it. Currently uh I'm the user and for this particular user path I'm
20:40:54
trying to generate the news feed. This path is currently following 10 different
20:41:01
people and all of these 10 different people they are also users on their own.
20:41:06
Now these 10 people whenever they tweet something they would have a tweet associated with their user ID. Okay. And
20:41:14
that association can be linked through the combination of user ID class and the
20:41:19
post class. Because remember even in the user ID class we are actually calling a
20:41:26
method to to create tweets and we can actually store those tweets inside the
20:41:31
user ID. So user ID knows that any for any particular user ID what are the
20:41:36
different tweets that that user has made. And let's say that uh some users just made one tweet, some user made
20:41:42
bunch of different tweets and then some user made u few more tweets something like this. So now we can go we can go to
20:41:51
any particular user that is option number one. Through this user we can find all the people I'm currently
20:41:57
following. That is second step. Through finding all the people I'm following, I need to find all the tweets that they
20:42:03
have made. That is the third step. after fetching. So let's say I identify that
20:42:09
uh so far all the people I follow they have in total made 50 different tweets.
20:42:14
Now amongst these 50 tweets I want to find that what has been the top 10 or
20:42:19
let me use okay most recent 10 uh tweets that has been uh generated. So for in
20:42:25
order to find the recent 10 tweets the logic is quite simple. I put I take all
20:42:31
of these 50 tweets I create a heap. Now we all know the concept of heap or heap
20:42:36
or a priority cube. Now inside this heap or a priority cube I store the values
20:42:43
based on the time they arrived in. So the value that came in at let's say time
20:42:48
1 second and the value that came in let's say at time 3 second. So the 3cond
20:42:54
should come in before 1 second. And this process can be easily m maintained and
20:43:00
manipulated by heap because it's a comparator type of data structure where
20:43:05
you can compare between any two values and store the values in some sort of sorted format. So in this case the
20:43:12
sorting is going to be done based on the time that it came in and it is actually going to be in the descending order. So
20:43:19
the value that came in at the latest time should be uh at the beginning and the value that came in later should be
20:43:25
towards the end of the heap. And then once I have entered all of these 50
20:43:30
values inside my heap. Then uh in order to generate the news feed I simply have
20:43:36
to fetch or I simply have to pull the top 10 values and that should be able to
20:43:42
generate the entire tweet. So now I have some sort of rough way and idea to solve
20:43:49
all these four methods. Remember once again uh let's try to reiterate and the
20:43:54
reason I'm doing this repeat repetitively again and again is because this question is extremely important and
20:44:01
I really want you to understand the whole logic and the whole thought process because we are using a great
20:44:07
number of combination of data structures to to achieve what we want. Okay. So for
20:44:13
the unfollow and follow method we are currently simply using the combination
20:44:19
of that for any particular user user is associated with a hashet of all the
20:44:24
people that that currently user is following and then we can very easily follow and unfollow people around. Okay.
20:44:31
In order to post tweets, we are simply relying on the concept or the connection between a user and a tweet and we are
20:44:40
combining everything based on uh the user ID and tweet ID and even in the tweet we are also associating the time
20:44:46
associated with that particular tweet. So we can very easily put it inside the hashmap. And the last thing is in order
20:44:52
to generate the news feed we are working with a heap and we are also working with
20:44:58
iterating over any particular user and for that user we are going across all
20:45:04
the people that this user is currently following and after finding that information going to those followers and
20:45:11
trying to find all the tweets that they have made. put that those tweets inside
20:45:16
our priority queue or a heap and then only fetch or pull top 10 out of this
20:45:23
particular heap and that should give us the the generated news feed in a linkless fashion but we still are
20:45:31
missing one key portion. How would in order to do these operations? How would
20:45:37
we know that for any particular user what are all the users associated with
20:45:42
that or how for user ID what is the user ID class and then what is the
20:45:47
information being followed. So we need some sort of mapping structure over here as well and for that what we are going
20:45:54
to do is we are we will first of all have to create a hashmap where inside the hashmap we know that this is a key
20:46:00
value based data structure. So as part of the key we are going to have a user ID and as part of its value we are it is
20:46:08
going to point to that particular user class or the user object that we have
20:46:13
created and once connected being connected to that particular user then
20:46:18
we should be able to find associated uh people that are being followed by that particular user and the tweets that are
20:46:26
being made by that user and by going to those followers we can also find their
20:46:31
tweets and all all of those things. So we are and now in total you know we are
20:46:37
actually using like five six different data structures. We are using a hashmap, we are using a hashet, we are using
20:46:43
priority Q, we are using uh what do we call link list and we are using like all
20:46:49
sorts of practices to make everything work together. So this is a brilliant question in my opinion. this question
20:46:56
can help you in lot of different ways and that's why I spend so much time explaining all of these different
20:47:02
concepts and different scenarios. Uh I hope you've understood my explanation.
20:47:07
If you still face some issues just write it down in the comment and I will be more than happy to answer your
20:47:13
questions. But now I think it's time that we start seeing the coding solution for this and it would start making more
20:47:19
sense that why did we do what we did. Okay.
20:47:29
Okay. So this is our Twitter class and uh we first of all initialize a static
20:47:34
timestamp. Initialize the value at zero and then we are simply going to update the value by one. Uh so we can uh keep
20:47:41
track of the time. Now let's try to understand how does our user class looks like. As specified we are going to have
20:47:47
an ID for any particular user. We are also going to have a hash set where we
20:47:53
are going to store all the people that are currently being followed by this particular user ID and we are also going
20:47:59
to make a reference to the tweet or the tweet class. Now let's see that for this
20:48:04
particular user we are also initializing a constructor where we are simply providing the value of ID and we are
20:48:11
also creating a new hashet for any particular user plus we are also adding the value of this particular user in the
20:48:18
hashet because a user should follow themselves. So that's a simple value and
20:48:23
then as a head of the tweet or the very first element inside our tweet link list
20:48:29
we are simply marking the value as null. Okay. Now for the follow method, we are
20:48:34
simply adding the value to the hash set. This follow hash set that we have created. For the unfollow method, if the
20:48:41
value does exist, we uh we are simply removing that value from the hash set. So follow and unfollow are pretty simple
20:48:47
from the point of view of our uh user class. And then we are also m making one
20:48:53
more method called post where we are providing the id and we are creating a new instance or of a new tweet
20:49:01
associated with this new ID that is being provided and then we are marking the new tweet that we just created as
20:49:09
the head of the new tweet. So we are just this is just an intermediate step but basically the tweet head is going to
20:49:16
be the new tweet that we just created. Now let's talk about the second class
20:49:21
that was our tweet tweet class that we talked about. Number one, we are going to have a tweet ID or just like ID for
20:49:27
this. Then we are going to be dealing with the timestamp. And since this is a link list type of structure, we are also
20:49:33
going to have one more node pointing to the next tweet in line. We are also going to have a constructor where we
20:49:40
simply provide the ID of the tweet and then we are going to mark add the value. We are also going to update the
20:49:46
timestamp and we are also going to point the next value to the null. Uh notice that we we are already pointing to the
20:49:53
tweet method using the user class that we have created. So we should be able to tweet for any particular user. Now we
20:50:02
have since now we have both of our classes ready. Now we are going to generate a user map where we are going
20:50:07
to have an integer ID as the as part of the key and we are going to have associated user as part of its
20:50:15
associated value and now we are going to be working on our Twitter class. So
20:50:20
first of all we are going to initialize our initializing our hashmap that we just created and then we will start
20:50:27
implementing all the methods that we talked about one by one. So first method is post tweet method where we simply
20:50:34
have a user ID and we simply have a tweet id. So first thing we are doing is we are going to check that if in our
20:50:41
user map uh do we have this user ID as part of one of the users that we have
20:50:46
created. If we don't have it then we are first going to create a new user. After
20:50:52
creating a new user we are going to put that value inside the user hashmap that we have created. And let's say that so
20:51:00
now we we do have an existing user. Uh and in either case if we have whether we
20:51:06
have an existing user or not we would create an existing user. Once that is done for that existing user we will try
20:51:13
to find its information and then we would call the post method inside the user that we have created. Uh that is
20:51:20
this method I'm talking about where we are creating a new tweet. Okay. So this is how the post tweet method is going to
20:51:28
work. Next logic is that we need to retrive 10 most recent tweets uh in the
20:51:34
user's news feed. So this is a complicated task. For that number one thing we are going to do is have a link
20:51:41
list where we are going to be storing the news feed. We are going to check that if for this particular user ID if
20:51:47
we don't have it as part of the news user ID we can simply return a blank newsfeed. If that is not the case, we
20:51:54
will first have to create a new hash set to store the information of all the users that are being followed by our
20:52:02
user ID that is provided as part of the input. So we find that information. We
20:52:08
also we also create a new heap or a priority queue where we are going to store the information based on the
20:52:15
timing. So the value with higher timing would come in before uh and the value
20:52:21
with lower timing should be should stay on the back end side. Once we have all
20:52:26
the data structures ready then we are going to first of all go through every single users that we are currently
20:52:33
following for this particular user ID and iterating over each one of them we
20:52:39
will get all the tweets that they have created. So we are going to go over the tweet link list that they have created
20:52:46
and if the given tweet is not null we are going to add those values to our
20:52:52
tweets. So now we have uh tweets being populated. Uh and once we have those
20:52:58
then we are simply going to have initialize a counter on top of it. We
20:53:03
are simply going to check that while the count is less than 10 we are going to go over all the tweets. We are going to add
20:53:10
all of those tweets to the news feed that we have created and we are going to be updating the counter. And how we are
20:53:17
going to be able to do that? Because remember inside our tweet heap that we have created all the values are sorted
20:53:23
in chronological order based on the most recent time stamp. And then uh once we
20:53:30
simply check that if we find that the weather count is 10 then we can simply uh get out of the loop. If that is not
20:53:38
the case and if the tweet next is not equal to null we will simply add that value to the to our tweet heap as well
20:53:45
and that's it in the end we can simply return the news feed. So we took care of the two most complicated problems and
20:53:53
then working on the follow and unfollow method is quite simple and straightforward. For follow method we
20:53:59
are first of all going to check that if the person who is trying to follow someone else does that person exist or
20:54:06
not. If that person does not exist, we will create them. Same way, if the person we are trying to follow, if they
20:54:13
also does not exist inside our hashmap, we would create them. And once they both exist inside our hashmap, we are simply
20:54:20
going to call the follow method for any for our user. And we are going to have
20:54:25
like follower and follower setup. Same way in the reverse order, we would simply call the unfollow method and uh
20:54:32
then that user would not no longer be followed. And that's it. That is the whole solution. I know it looks
20:54:38
complicated that we have to play we have to create a user class and then we have to create a tweet class and then we have
20:54:44
to create a Twitter class and then we will have to generate all of these four methods. But if you try to think it from
20:54:52
the perspective of like regular logic that if you are the developer of Twitter and you are trying to improve the system
20:54:58
or you are trying to implement it, how would you do that? So then you would gain much more beautiful insights from
20:55:04
this problem. So let's try to run this code.
20:55:12
Okay, seems like our solution is working beautifully. Let's submit this code.
20:55:18
And our code runs pretty fast compared to lot of other solutions in terms of time complexity. It is also excellent in
20:55:25
in terms of space complexity as well. Once again, this solution is present inside at our GitHub repository. So the
20:55:32
link is in the description. Feel free to go and check out that GitHub repository. I know it is going to be really helpful.
20:55:38
And uh let me know in the comments if you find this question interesting. Did I explain it well? Did I messed up or
20:55:45
whatever your thoughts are. Okay, thank you.
20:55:59
Hello friends, hope you're having a fantastic day today. So now we are going to do a full course on the tree data structure and trust me after this you
20:56:06
would become a master in all sorts of tree related interview questions. In this course we will learn what is the
20:56:12
trees, what are different types, characteristics, when to use it, benefits, limitations and what are going
20:56:18
to be the time and space complexity of different operations plus how to do different types of traversal, how to
20:56:24
solve different kinds of questions. We are going to cover every single topic. So without any delay, let's get started.
20:56:32
Tree is a very unique data structure and if we see the categorization of tree, it is defined as a nonlinear data
20:56:39
structure. It is very closely associated with graphs with some differences that we are going to learn later in this
20:56:44
course. Typically we use trees to define relationships and these relationships
20:56:49
are typically hierarchical in nature. Now these can be anything. You can think of a family tree or you can think of a f
20:56:57
file system or you can think of a uh structure inside a company or an organization and stuff like that. But
20:57:04
typically a tree usually comprised of two entities. First one is called nodes
20:57:09
that we typically define by these circular items. And then second one is the edges between the relationships and
20:57:16
these relationships inside a tree are parent and child based relationship
20:57:22
where every single node can be a parent or it can be a child or it can be a
20:57:27
both. So in this case the very first child would be the root node and then it has now it has two subsequent children
20:57:34
and then these children can have children of their own and so on and so forth.
20:57:41
Now let's learn some terminology associated with trees that will help us understand better about different
20:57:47
concepts. So first let's understand that what are the different types of nodes available. Now very first one is a root
20:57:52
node. Root node is parent to every single node that is going to be the top node inside a tree and this is going to
20:57:59
be the gateway point through which we can enter tree and then traverse over all the other remaining values in
20:58:05
different fashion. Next is a parent. Now any node can be a parent as long as it
20:58:11
has child of its own. So in this case this is a parent node. This is a parent node. This is a parent node and this is
20:58:17
a parent node. But these two nodes or these three nodes are not parent node because they don't have any children
20:58:23
associated with them. Next we have child. So every single node can be a child node except root node because root
20:58:30
node would be sitting at very top. So it does not have any parents of its own. But currently like these two nodes are
20:58:37
going to be children of the root node. Then these two nodes are going to be children of this particular node. So on and so forth. So that can keep on going
20:58:44
on and on. Next is a leaf node. So leaf node are the nodes that are that sit at
20:58:50
the very bottom of the tree that does not contain any child of their own. So these are defined as the leaf nodes. Now
20:58:57
the concept of sub tree. So subtree can be part of any existing tree. So we can
20:59:03
define that for any particular parent. So for this particular root node we can say that this is one of the subtree of
20:59:10
this particular node because it is part of its hierarchical structure. Same way for this particular node. It only
20:59:16
contains this node as part of its sub tree. Nothing more than that. Then we need to there is a concept of height of
20:59:23
the tree. So height of the tree is the longest distance we can make for any particular node from its root. So in
20:59:31
this case if we have to calculate height at this level height would be one. At this level height would be two. And now
20:59:37
notice we still have one more node at this level. So height is going to be three. So in this case we can define
20:59:42
height to be three. Even though we still have nodes that are going to be at lesser heights then uh we have depth of
20:59:48
a tree. So depth of a tree is that for any particular node what is the distance
20:59:53
from its root node. So we can say for this node the depth is going to be two because it is two steps away from the
20:59:59
root node. Same way any this node is going to be one step away from the root node. So the depth of this node is going
21:00:05
to be one. And last one is a degree. So degree is defined by the number of child
21:00:11
any particular node has or any particular tree has in their structure. In this case we can define that this
21:00:17
node has a degree of two because it has two child. Same way this node has a degree of two. But in this case this
21:00:24
node only has degree of one because it just has one child. So the these are the terms that you will need to understand.
21:00:34
Now let's learn that what are the different types of trees available. First one are the general trees. We can
21:00:40
have a root node and then it can have any number of child of its own from zero to n. It can have one child. Some nodes
21:00:48
can have like five childs. Some node can have just uh no child at all. Some nodes
21:00:53
can have like 50 child so on and so forth. So there can be many relationships and it these can be very
21:00:59
complicated. But we see all sorts of scenarios where we need to implement trees like this. Second one is a very
21:01:06
restrictive tree that is highly used in technical interviews and also in real life and that is binary tree. So binary
21:01:13
tree has a simple formula that every single node must have at most two child
21:01:19
or less than two. So let's say in this case this is going to be an example of a
21:01:25
binary tree where we have nodes like these where each of the node either has at max two child or less than two child
21:01:33
and uh this is like a good example because every single node either has uh two child or less than two child. Next
21:01:39
one is a turnary tree. This is just for an example sake. In this case every node are going to have three child at mo most
21:01:47
nothing more than that. So they can have two child, one child or no child at all but overall not more than three child.
21:01:53
So this is a very similar example to binary tree. And same way we can define as n tree. So where n can be any value.
21:02:01
If we define n to be five then at any given moment any particular child can have at most five any particular node
21:02:08
can have at most five children and nothing more than that. So there can be many examples. And then there is a
21:02:14
special type of tree that is binary search tree. This contains a very special property where we are going to
21:02:21
have a scenario where the value is going to be determining the structure of the
21:02:27
tree and of course this is a binary tree. So at most every single node can have either two or less than two child.
21:02:34
Okay, that is a given fact. But on top of it for every single type of node
21:02:40
value we are going to follow a strict principle that any particular value that
21:02:45
is currently present on the left child has to be less than the root node and any particular value that is currently
21:02:52
present on the right child has to be greater than root node. So root node the
21:02:58
value is going to be that left child is going to be lesser than the root node that is going to be lesser than the
21:03:03
right node right side node and let's see the an example of this in action. Let's say currently we are given a value five
21:03:10
as a root node. So we can guarantee that no matter how many entries are currently
21:03:15
present on on the left side of it all of these entries are always going to be less than five value number five. Let's
21:03:22
see an example of this. Let's say we can have a node like this that is value is three. Once again for this three we are
21:03:27
going to follow the same principle that everything on the left of the three is going to be less than three. So this can
21:03:33
be value two and then then this can be value one and then this everything on the right of this three has to be
21:03:40
greater than three. So this let's say this value is four. Now we can think that six is also greater than three. So
21:03:47
can we put six over here? No. Why? because we are still following the same
21:03:52
principle all the way up to root level. So even though this value is going to be right of this particular tree, it is
21:03:59
still going to reside on the left side of this particular five tree. So this value also has to be less than value
21:04:06
number five as well. So this value can be four. And same way on the right side we can follow the same principle where
21:04:12
every single value is going to be greater than five but there can be some like variations on the on its own. So
21:04:19
let's say that this value is currently eight. Then the left of eight is going to be value number six. The right of
21:04:25
eight is going to be value number nine. And then the value at the right of this
21:04:30
six can be value number seven. Because notice now in this case for eight every
21:04:35
single thing on the left of the eight is still going to be lesser than eight. And where we are following the same
21:04:41
property. So now notice that if you traverse this particular tree in like
21:04:47
this fashion then you will find a sorted entry and let's just try to quickly see
21:04:52
that that the very leftmost value is going to be the smallest value and then it's uh subsequent way so we are going
21:04:59
to traverse like left then if there is nothing left on the left then we are going to iterate its root and then we
21:05:05
are going to iterate its right child and this traversal mechanism would actually
21:05:11
allow us to get a sorted result or a sorted value for all the values that are
21:05:16
present and we are intentionally maintaining this property. So now I went
21:05:21
a step ahead and actually just showed you that what does uh traversal mechanism looks like and this is
21:05:28
actually an in order traversal. Uh don't worry about the word I'm going to explain this in very much detail in
21:05:35
subsequent parts. But remember that we can have a binary search tree that is
21:05:40
going to allow us to have a sorted property being stored amongst different
21:05:45
values that are currently present inside the tree.
21:05:51
Now let's quickly learn that what are the different types of binary trees because sometimes there can be questions
21:05:56
being asked from these topics. So first one is a full binary tree where every single node either has zero child or two
21:06:03
child. So we can notice an example like this where this particular node has zero child. Apart from that and also this
21:06:09
node has zero child. This node has zero child but apart from that every other node has exactly two childs at the
21:06:15
moment. We never have a scenario where we have only one child hanging. Okay. Next one is a complete binary tree where
21:06:22
all the levels are completely filled except the last level that is filled from left to right. So we can notice
21:06:28
that okay this level root is completely filled. This level has two child that is completely filled. Now this is the last
21:06:34
level. So all the nodes are filled from left to right and then we have one node that is currently not present. So
21:06:40
basically there can be many examples. Next is the most beautiful type of tree that is called perfect binary tree. So
21:06:46
all the internal nodes has exactly two children and last level is all leaves
21:06:52
that are completely filled. So basically this is like the most good-looking tree out there that where every single node
21:06:58
has two ex exit two child and then leaf node has no child at all. So this is perfect binary tree and then we have a
21:07:05
balanced binary tree which is actually a very popular lead code problem that we are going to solve later on. But over
21:07:11
here the thing is height difference between left and right subree is at most
21:07:17
one nothing more than that. So we can notice that for this particular node the sub trees are going to be this one and
21:07:23
this one and we can see that the height of this particular sub sub tree compared to root is going to be three for this
21:07:30
node and then for height of this is going to be two. So at most we have difference of two. But if we had one
21:07:36
more node like this then the height of this would have become four and this would have become two. So that would not
21:07:42
work. So that is like an example of different binary trees.
21:07:50
Now for this tree data structure we will need to find a way to iterate over all the nodes and then try to find the
21:07:56
meaningful information. So there are different tree traversal techniques available to us. We are going to learn
21:08:02
all of these in depth. So they are in order pre-order post order and then an
21:08:07
extra one level order traversal. We are going to use this example. So notice that this one I have taken as a binary
21:08:14
search tree as part of the example but overall it makes no difference on whatever type of tree we are trying to
21:08:19
traverse for. So first one is an in order traversal. We follow the technique that first we are going to traverse the
21:08:26
left child. So as long as left child exist we are going to keep keep on going in that direction. Then we are going to
21:08:33
visit the root node and then we are going to visit the right child of the node. And notice that root comes in
21:08:40
between left and child. And that's why it is defined as in order traversal. Position of root is defined as what it
21:08:47
is what it is. So notice that currently we are going to be starting our journey at the root root node. We have a left
21:08:54
child. So we will go to the left child. Once again the left child also has a left child. So we'll go to that left
21:08:59
child. And now notice that this does not have any more left child to visit. So now we are going to mark this node or
21:09:07
traverse this node. So first node we are going to visit is going to be value number one. Then we are going to
21:09:12
continue our journey in the same fashion and we are going to go back because this
21:09:18
does not have any more subsequent children. Now we are at this position number two. Once again we will follow
21:09:24
the method of left root and right. But notice that for this particular two we have already visited left node. So now
21:09:30
we can visit this node. So then next node would be two and it still has a right node that we haven't visited. So
21:09:37
we will once again visit node number three and mark it visited. Then for this
21:09:42
now notice for three it does not have any subsequent children. So we will go back. We already visited two. So so now
21:09:47
we will go back again. Now this four we haven't visited but we visited all of its left child. So then we will visit
21:09:54
four. And now after this we are we will start visiting its right subree or right child. So then we are going to come at
21:10:02
value number six. Six also has a left child five. So we will visit five first and then we will visit six and then we
21:10:08
we will visit seven. So notice that because this was a binary search tree and we did in order traversal, we
21:10:15
basically sorted all the values that are present inside the tree. So look how beautiful it looks. Now let's understand
21:10:22
the pre-order traversal. Now the positioning of root slightly changes. First we are going to visit the root
21:10:28
node. then we will visit its left child and then we will visit its right child and uh so now let's logically start
21:10:35
iterating. Now notice that the entry point towards this iteration is going to be through the root node. So first we
21:10:42
are going to visit node number four over here. After visiting four, four does has
21:10:47
left child. So then we will go to the left child once again. We are going to follow the same method and we will visit
21:10:53
node number two. Then we will go to left child and we will visit node number one. Now after visiting this, this does not
21:10:59
have any more children of its own. We will go back. We have already visited two, but it does has a right child that
21:11:04
we haven't visited. So we will visit this. And then once again we will uh go
21:11:09
back. We have already visited this. And now we will repeat the same thing with its right subchild. So first we will
21:11:15
visit node number six, then we will visit node number five and then we will visit node number seven. And this is
21:11:20
going to be the visited path. Same way we have post order traversal. Now this one is slightly different because first
21:11:27
we are going to visit left child then we are going to visit its right child and then in the last we are going to visit
21:11:33
the root node. So as long as left or right child exist we will have to visit both of them. So we our entry point
21:11:40
would be at the starting position four. It does have a left child or left children and right children. So we will
21:11:46
have to visit each one of them. We go to two. Once again it has left child. So we will have to go and we come at value
21:11:53
number one. one does not have any child of its own. So now we we will visit one
21:11:59
as the first node. Then because remember we will go back but this for this route
21:12:05
number two we still have a right child that we haven't visited and and remember the order is left right and then root.
21:12:11
So we'll visit the right child and then we will visit node number two because we have visited all of its entry. Once
21:12:17
again we will go back. Now though for this four we have visited all everything on the left we haven't visited the right
21:12:23
subary so we will vis repeat the same process we will go down to six six still has a left child that we haven't visited
21:12:30
so we will go to value number five first after that we will visit value number seven first and after that we will visit
21:12:36
value number six and in the end very last value would be visited value number four so this would be the post orderer
21:12:43
traversal and last one is a level order traversal we can also define this as a
21:12:48
breath first search as well approach because we are going to go down in breath for any particular node. So once
21:12:55
again we are going to start iterating in the root but now we will iterate level by level from left to right. So first we
21:13:02
will visit node number four then we would visit uh the its child so node
21:13:07
number two and node number six. Then we will visit all of these values from left to right fashion. So 1 3 5 and 7. So so
21:13:14
on and so forth. This is also another technique that is pretty popular with basically graph related problems but can
21:13:20
also be applied to trees tree problems as well.
21:13:26
Now let's understand that what are the different operations we can do on trees and what is going to be the time
21:13:31
complexity. Now the binary search tree is a special case and the regular trees
21:13:37
are a separate case. So we will treat both of them slightly differently and I would provide time complexity for each
21:13:43
of them. In the example, I have only shown you binary search tree but it can be true for regular trees as well. So if
21:13:49
you have to search for any particular element in a binary search tree, it is going to be very simple because we are
21:13:54
simply uh break moving away for 50% of uh all the nodes in one single go. If I
21:14:02
have to search for node number three at root position, I simply have to check that whether three is less than four or
21:14:07
not. If it is less than four, then I can only need to check in this portion. I can completely eliminate all of these
21:14:12
values. So that is going to be very powerful. So basically for binary search tree the search operation is going to
21:14:19
take uh on an average log log end time. So which is pretty fast significantly.
21:14:25
But for any regular tree where we don't have such structure being maintained it is going to take big of end time in the
21:14:31
worst case scenario. Same way for insertion it can be typically done in log of end time because we need to find
21:14:37
where we need to add that value and we can do it quite quickly. Sometimes you will have to adjust the existing nodes
21:14:43
but overall on an average case this will work in login time but for regular scenario. Now how you are inserting the
21:14:50
value is also a concern. If you're just inserting value at any position randomly we can typically do it in big of one
21:14:57
time on an average case. But if you need to add it only on the available leaf nodes with some condition in the worst
21:15:03
case scenario this can become big of end time for different tree operations. Same way for deletion it is going to be login
21:15:10
time but for this one it is going to be big of end time because first we'll need to find the value where it exists. So
21:15:16
finding will take lot of time and traversal will take big of end time no matter what because we need to iterate
21:15:22
over every single node that is currently available. So these are the common operations that you can typically do
21:15:28
with different trees and it has different time and space complexities.
21:15:35
So typically trees and graphs fall under the same categorization and both deals with relationships. The only difference
21:15:42
is with trees all the nodes are going to be connected and all the nodes are
21:15:48
guaranteed that they won't be forming any particular cycle. So there are no cycles in a tree and all the nodes are
21:15:55
basically connected. graph does not have any such conditions. Which means we can
21:16:00
have a graph that looks pretty similar to a tree but uh we can have some more
21:16:05
nodes that are basically not connected with each other or we can have graph that has all the nodes connected but it
21:16:12
can have some cycles as well. So trees does not have any such kind of condition and typically for trees we are only
21:16:18
dealing with parent child relationship. So there is no room for uh cycles.
21:16:26
Now there are two pretty popular type of trees or variations of trees that is
21:16:31
real use cases and they are quite popular with all sorts of popular applications and interview questions.
21:16:38
First one is a structure called tries where we have a parent child relationship but this is typically
21:16:44
working in tandem with strings and for each of the string every single character is being treated as if it was
21:16:52
a node inside that particular string and then it has subsequent children of its own. So let's say if I have to talk
21:16:58
about a string uh that looks like rat that is going to store the value for rat
21:17:04
then I would have a root node that is going to be empty then it is going to have a subchild that contains value r
21:17:10
and then another subchild and then another subchild now let's say that I want to create uh another value that is
21:17:17
rattle then in this case for this I'm also going to have one more variation
21:17:23
where this is going to be pointing towards a null value. This is where it defines that this is one of the
21:17:30
variations of the word and then it is also going to have subsequent words as t and then uh l and then e and uh same way
21:17:39
you can store bunch of different applications and then there is going to be a null value over here to point that
21:17:44
this is also a full word in on its own. Now you can imagine that there are thousands of applications or companies
21:17:51
that are currently using this principle to generate something uh called autocorrect where based on your current
21:17:59
input we can autocorrect or auto suggest that whatever you are trying to type and
21:18:05
then automatically adjust those values. You can think of applications in all sorts of mobile and web and iMes and
21:18:11
WhatsApp they all use the same principle. So you can imagine how popular this technique is. Hello
21:18:17
friends, we are still not employed by a fing company. So let's not solve lead coding till we get there. Today we are going to do maximum depth of binary tree
21:18:23
lead code problem. And if we see some of the companies where I want to get a job who have already asked this question, there are companies like LinkedIn,
21:18:29
Amazon, Microsoft, Google, Facebook, Apple, Bloomberg and Uber. So that's why
21:18:34
I'm paying my utmost attention. I hope you also enjoy the video.
21:18:40
So this is a lead code easy problem and also very well-liked problem on lead code. If we understand the problem statement, basically we are given the
21:18:46
root of a binary tree and we need to return its maximum depth. Now we are also given the definition of what a
21:18:51
maximum depth is. It is basically the number of nodes along the longest path from the root node down towards the
21:18:57
farthest leaf node. That is the depth of the tree. And uh if we try to understand this with an example, suppose we are
21:19:03
given a tree over here that looks like this. In this case, the maximum depth is going to be three. Why? Because the
21:19:08
nodes at the root level is currently at position one or height one. uh the root at this level is at depth two or height
21:19:16
two and root at this level is actually at depth three. So in this case we need to return three as the answer because
21:19:21
three is the maximum depth we can get from this root node. So let's see that what would be the different approaches
21:19:28
to solve this problem. Okay suppose this is the input we are given and we are trying to find the
21:19:34
maximum depth for this particular given tree. Suppose this is the root of the tree. If you want to find the maximum
21:19:39
depth for this tree, the answer is going to be four because of these two nodes. Uh we can see it clearly over here that
21:19:44
over here the value is one, this is two, this is three and this is four. And this is the answer we need to return. The
21:19:49
question is before we return this answer, we will actually have to build some intuition behind it. And the intuition is suppose at this position
21:19:56
number five if you want to determine that what is the maximum depth over here. Well what we can do is we will check on the left side we will check on
21:20:02
the right side and whatever has the greater number of nodes on either side
21:20:07
we will actually take that as maximum depth and we will do it plus one. Well in this case the six and seven both are
21:20:13
located at the same position. Six and seven none of them has any children which means that over here we can
21:20:19
determine that this is actually one and this is also one. So on the left side and on the right side both values are
21:20:25
actually one. So what we can do is we can do 1 + 1. So 1 + 1 will give us the answer that the maximum depth has at
21:20:32
position number five is going to be two. So in this case okay we have found the maximum depth over depth over here to be
21:20:38
two. Well if we take this value number four at this value number four it does not have any more children. If it does
21:20:43
not have any more children which means we can determine the maximum depth in this case is going to be one. Well, now
21:20:49
we have these two values that now based on these two values, it becomes pretty easy for us to identify that what is the
21:20:54
maximum depth at this position number two. All we will have to do is we will take whatever the maximum value amongst
21:21:00
these two is. Maximum value is actually two. So what we can do is we can do 2 + 1 and 2 + 1 is actually going to be
21:21:05
three. So we can determine that three is going to be the maximum depth we can achieve at this node number two if this
21:21:11
was to be the root of the given tree. And for this position number three, the maximum depth we can achieve is only one
21:21:17
because it does not have any more children. Uh so that is a given fact. Now we have these two information. Now
21:21:22
it becomes pretty easy for us to identify that what is going to be the maximum depth at this position number one. And uh we all we will have to do is
21:21:29
take the maximum amongst these two values. So maximum value is going to be three. And all we need to do is just
21:21:34
plus one. So if we do 3 + 1, we will get the answer four. And four would be the correct answer in this case. And that is
21:21:39
what we are going to return. So the maximum depth we need to find we can simply do it by using this method. Well
21:21:47
uh now if you see for this particular solution we are actually able to achieve this solution. But what we are doing is
21:21:53
that at any given position we are seeing that what is the left max value or right
21:21:58
max value and whichever is greater amongst either one of them we are taking that and we are adding one. one. Now
21:22:04
again we are repeating the same process that we are taking the left max and right max value and again we are adding
21:22:10
one. So which means that in order to solve a bigger problem we are actually solving a smaller problem and then again
21:22:16
a smaller problem. So basically we are doing recurs we are doing it recursively and that is how we are going to solve
21:22:22
this problem using recursion which is very powerful and it is highly used in different kinds of tree tree problems.
21:22:29
So that is how we are going to solve this problem and this would be the optimal solution we can use. uh if we see the time and space complexity in
21:22:35
this case, the time complexity is actually going to be big of n because we will have to iterate over every single element in order to get the answer. And
21:22:41
if we see the space complexity in this case, the space complexity is also going to be big of n because we might have to
21:22:47
store all the values inside our recursive function. And uh this approach is actually very good. It works as
21:22:52
expected. There is also one more approach which uses stacks and that does not use recursion. It actually use uh
21:22:59
iterative function. So let me know in the comments if you want to see the stack solution as well. And I can also explain that but for now if you show
21:23:06
this recursive solution in in any interview the interviewer would be more than happy. Uh so let's move on to
21:23:11
coding now.
21:23:23
So first of all we are going to take care of a edge case. If that is not the case we will have to
21:23:28
call our recursive function. First of all, we are going to have an integer called left max that is going to take
21:23:33
care of the left sub tree for any given root position. And we are going to call our recursive function again. And same
21:23:40
we are going to do for the right sub tree as well. We are going to create a parameter called right uh max
21:23:47
and in either case all we have to do is simply return whatever the maximum value we can we are able to find and then we
21:23:54
will add one to it. And this should be it. Uh once we get out of the loop, our
21:24:00
solution would be done. So let's try to run this code.
21:24:06
Okay, seems like our solution is working. Let's submit this code. And our code runs as expected and it's
21:24:13
actually pretty fast compared to lot of other solution. So I'll be posting this in the comments so you can check it out from there. Thank you.
21:24:26
Hello friends, we are still not employed by a fing company. So let's not stop lead coding till we get there. Today we are going to do same tree lead code
21:24:33
problem. And if we see some of the companies where I want to get a job who have already asked this question, there are companies like LinkedIn, Amazon,
21:24:39
Google, Bloomberg, Apple, Microsoft, Facebook and Uber. So that's why I'm paying my utmost attention. I hope you
21:24:45
also enjoy the video. So this is a lead code easy problem and as the name suggest same tree. The
21:24:52
problem is self-explanatory but let's go over it that basically we are given two roots of a binary tree called P and Q
21:24:58
and we have to write a function to check if they both are same or not. So let's try to understand this with couple of
21:25:03
examples that are given over here. Over here here we are given this two trees P and Q and in this case we see we can see
21:25:09
that both of these are one both of these are two and both of these are three. So we can say that okay they are actually
21:25:14
same and we can return true in this case. But for the second example, if we see the P and Q values over here, 1 one
21:25:22
is same. So root values are same. But if we see over here, this is actually two and this is actually true. Despite being
21:25:27
the same value, the positioning is not same because this is actually the left child of this given P tree and this is
21:25:34
actually the right child of this given Q tree which means that these two are not same. So in this case, we will return
21:25:39
the false and this is what we have to achieve. So let's see that what would be the different approaches to solve this problem.
21:25:46
So solution of this problem is actually quite simple and if we see the approach one we are going to use an iterative
21:25:52
approach. In the iterative approach what we are going to do is we are going to iterative over both of these given trees
21:25:57
in the same manner and we are going to keep on checking subsequent uh nodes of every single position. At any given
21:26:03
moment if we identify that any single node does not match we can return false immediately. And if somehow we can reach
21:26:09
out to the end of the tree and iterate over every single nodes we can return true in this case. So let's see that in
21:26:16
action. Uh so first of all we are at this P for this P and Q tree currently we are at this root position. So we will
21:26:22
check that value and both of them are actually one which means we are good so far. Now we are going to iterate over on the left side. So on the left side this
21:26:29
value is actually two and this value is also two. So again we are good. Now again on the left side this value is
21:26:34
actually three and this value is also three. So again we are good so far. Now we go back and now for this position
21:26:41
number we also have a right sub tree or so we will check that right position this is five and this also has a right
21:26:48
position which is also five. So so far we are good. Now again we go back to this root node. We still have this right
21:26:55
side that we haven't traversed. So this node is four and this node is also four. So again we are good and at the end this
21:27:01
node is six and this node is six. Now we don't have any more nodes to go back to. So essentially we have traversed over
21:27:07
all the nodes inside given both the trees. So we can return true in this case and this is the approach we are
21:27:12
going to take. Uh let's see what would happen in a scenario where trees don't match up. So here I have drawn that
21:27:19
example as well that over here all of these nodes are same. Uh but actually
21:27:24
this node and this node these two are not same. So because these two are not not same the moment we iterate over all
21:27:30
of these nodes and eventually we would reach to these positions we can return false immediately in this case. So this
21:27:37
approach would work as expected. And if we see the time and space complexity in this case the time complexity is
21:27:42
actually going to be big of n. Why big go of n? Because we will have to iterate over every single node inside the given
21:27:48
tree for both uh p and q trees. The space complexity would be big of login.
21:27:54
That is because this is a binary tree.
21:28:00
Well, in the second approach, we are actually going to solve this problem recursively. And the idea is at any
21:28:06
given moment, we have to identify that whether two given two trees are same or not. The thing we are going to do is we
21:28:12
are going to compare their root nodes. If they both are same, we will have to compare their entire left sub trees. uh
21:28:18
that they have to be the same and also we will have to compare the entire right sub trees that as they they also have to
21:28:24
be the same and if that is the case we can define that tree to be the same. But if we take a look at for the left sub
21:28:30
tree again we are going to repeat the same process that even for the left sub tree we are going to compare the root
21:28:35
nodes if they both are same then we are going to compare their left sub trees and their right sub trees to be the
21:28:41
same. So essentially we are doing the same thing repeatively for different kinds of input and recursion is the best
21:28:48
way to approach that. Uh and also your interviewer is going to expect you to do this recursively because that would be
21:28:55
more efficient way of doing it. Uh so let's see that in action. So the idea is at any given moment we are going to
21:29:01
compare the root node. So over here root node is same because root node is same we will have to check that whether the
21:29:06
left sub tree is same and right sub tree is same or not. So first we'll do the left sub tree. So now for the left sub
21:29:12
tree we have these two trees for P and Q respectively. So again we will check the left node. So left node is this two and
21:29:19
this is also two. So they both are same. Now we are going to check the left sub tree and right sub tree again. So this
21:29:24
both of these are three. So they we are good. Now we will have to check the right sub tree. So right sub sub tree is
21:29:30
also five and five. So again we are good. Now again so far we have calculated the entire left portion but
21:29:37
we haven't calculated the right portion. So now we will do that. So again for the right sub tree this value is four and
21:29:43
this value is four. So again they both are equal. So we are good so far and then these values are six and six. So
21:29:49
again we are good so far. Now we have iterated over every single node recursively. That is the important part.
21:29:55
And we have found all the values to be the same. So because they were same we can return true in this case and
21:30:01
everything is good. And at any given moment suppose we identify that any single node does not contain the same
21:30:07
value as its uh counterpart. Then the moment we are comparing these two values we can return false immediately and that
21:30:14
would be the solution for this problem. If we see the time and space complexity in this case the time complexity is also going to be big of n because we'll have
21:30:21
to iterate over every single value and the space complexity is going to be bigo of log n. So the time and space
21:30:27
complexity is not different than the iterative approach but recursive approach just is a lot less coding and I
21:30:34
will also be showing that in the code.
21:30:40
So first of all we are going to check that if the given P and Q both are null. If both are null we will have to return
21:30:45
true because essentially they both are same. If that is not the case and if any of
21:30:52
either P or Q is null and the other one is not null then in that case we will have to return false
21:30:59
and if both values exist then we will have to compare their values and if both values are not same we can
21:31:05
return false immediately. If that is not the case we'll have to iterate over left and right sub trees of
21:31:11
subsequent P and Q trees. So now we are going to make our recursive call.
21:31:19
And that's pretty much it. Let's try to run this code. Okay, seems like our code is working as
21:31:26
expected. Let's submit this code. And our solution runs pretty efficiently. It's actually 100% faster.
21:31:33
But that is not the case because runtime is 0 millcond. That's why it's showing 100% faster. I will be posting this in
21:31:39
the comments. So you can check it out from there.
21:31:48
Hello friends, hope you are having a fantastic day today. So now we are going to do a very popular lead code problem.
21:31:53
So without any delays, let's get started. So the lead code problem we are going to solve is called symmetric tree
21:31:59
and we can see that this is a lead code easy problem and also a very well-like problem on lead code. The problem
21:32:05
statement is very straightforward. We are given the root of a binary tree and we need to check that whether this
21:32:10
binary tree is a mirror of itself or not which we can see it from the example where notice that ignoring this root
21:32:17
node if we compare the sub trees of this root node we can see that they are exact
21:32:23
mirror copies of each other which means this left node is same as this right node. Once again this left node is same
21:32:29
as this right node and once again this right node is same as this left node which means we need to check that for
21:32:35
any single given tree whether this symmetric property is true or not and this is actually very simple to do. So
21:32:42
we are just going to do what we just used to explain this problem. If we understand we are given the root then
21:32:49
since this is a binary tree uh it can either have a left left node and right node and once again this left node can
21:32:55
also have a left node and right node and same goes with the subsequent trees and there can be many layers as many layers
21:33:02
as we want. The only condition we are checking is that for any single root uh
21:33:07
value, we can only say that the tree is symmetrical if its entire left subree is
21:33:15
also symmetrical with entire its right subree. And in that case we need to check that whether the left child is the
21:33:22
same as right child. And once again even at this subchild level we need to check
21:33:28
for the grandchildren. So once again even at this level we need to check that whether this left tree is same as this
21:33:36
right child and also this right child is same as this left child. If that is the case then we can determine that this is
21:33:43
a symmetric tree and we can keep on repeating or going down as many levels as we want but the core logic remains
21:33:50
the same which means number one we are doing two things. Number one, we are taking a bigger problem and we are
21:33:56
actually breaking down into subpros and we are keep on repeating the same process for all of its children. So we
21:34:03
are going to be using recursion to solve this problem. That is number one thing. Now number two thing is that we know in
21:34:09
the recursion we need two items. Number one thing is that what is going to be the base case. So base case is quite
21:34:14
simple. If any particular child does not have any more children or if the if
21:34:20
there does not exist any left or right node to check then we can get out of the loop and if we do get out of the loop
21:34:27
and everything remains the same which means we can return that this is a symmetric tree. That is option number
21:34:32
one. Option number two is that at every given moment we need to have a recursive
21:34:37
function based on which we are going to be making our recursive call. And what is going to be the recursive function in
21:34:43
this case that at every single root node we need to check that whether the left
21:34:49
child of root is same as the right child of root or not. And we are going to be
21:34:54
keep on repeating the same process once again at the root node. We are going to check that whether the left grandchild
21:35:00
of the root is going to be the same as the right grandchild of the root root or
21:35:05
not. So this is going to be our base case that the left child is equal to
21:35:10
right child and right child is equal to left child. This condition has to be
21:35:15
satisfied and then only we can keep on repeating the same process in the recursive manner and basically that's
21:35:21
it. So just the way I explained that let's take it let's understand this with some example. So suppose we are given a
21:35:28
value like five and then we are given subsequent values three and three and once again we are given further
21:35:33
subsequent values. Let's assume like uh four five and then this is also four five. So is this a symmetric tree? Yes,
21:35:40
this is a symmetric tree because both of these values are same. This is also equal to this one and this is also equal
21:35:46
to this one. Which means in this case we can return true. If we are given some other value. Let's assume that over here
21:35:52
we are given one extra child like six. Then we cannot complete the recursive
21:35:57
call because this right subchild still also has a left subchild. But that is not present over here. So we can say
21:36:03
that this is not symmetric. But in this case uh if we did had another child like
21:36:09
this then we could have said that this is also symmetric. So this is the logic that we are going to apply. Now let's
21:36:14
see the coded solution for this one. So first this is the definition of our tree node where every single node has a
21:36:20
value. It has a left child and it has a right child. Now let's see our solution. So for our is symmetric method uh we
21:36:28
need to return true or false or boolean value and in the input we are given the root of the given existing tree node.
21:36:34
Now first we are going to check for the edge case that if the given root is equal to null we can simply return true.
21:36:39
If that is not the case we are actually going to call our recursive method that is called is mirror where we are going
21:36:45
to pass in the left child and right child of our root node. Now let's see the recursive method is mirror. So as an
21:36:52
input we are having tree two tree nodes. Uh so first condition we are checking is that if the given left is equal to null
21:36:59
and right is equal to null. So both of the these entries are null. If that is the case we can simply return true that
21:37:05
saying that the tree has been is symmetric. If that is not the case we are also going to check that if only one
21:37:11
of them is null and the other one is not. If that is the case then the symmetry has been broken down. So we can
21:37:18
directly return false. If none of these cases are true which means we still have to perform our iteration. So first we
21:37:24
are going to check that if the given left dot value and the right dot value.
21:37:29
So value of this left node and the right tree node if both are same then we are
21:37:34
going to recursively call this is mirror method. For this is mirror method we are
21:37:40
going to take the left child of this left tree and we are going to compare it with the right child of this right tree.
21:37:47
And same way in the next iteration we are going to compare the right child of this left tree with the left child of
21:37:55
this right tree. So I know that this portion might look confusing but if you just try to understand this using the
21:38:01
image uh things will become much more simpler. And I forgot to mention one thing during the code that uh this code
21:38:08
actually runs in big of n time because we we are simply iterating over every single node just one time nothing more
21:38:14
than that. And in terms of space complexity this is also going to be big of n because in order to fulfill this
21:38:20
recursive stack we might have to use big of n space. Okay, so let's try to run
21:38:25
this code. Okay, our solution seems to be working as expected. Let's submit this code
21:38:34
and our code runs 100% faster than all the other solutions which is awesome and
21:38:39
pretty good. So once again I would be posting this solution in the GitHub repository that where we have which
21:38:45
contains all of the lead code problems that we have solved so far. Also I wanted to show you one more thing that
21:38:51
might be helpful for your preparation. That is this Google document that I have created which contains information about
21:38:57
some of the popular courses that I have created. But this is the most important part. This is the collection of 130 most
21:39:04
popular most asked and most promising questions uh that has been asked at interviews. I have broken down these
21:39:10
questions based on different topics and also I have provided the information that how many times these questions were
21:39:16
asked at specific companies. So this is going to be really helpful if you are targeting any specific companies or if
21:39:22
you are just targeting different topics or the depending on the different difficulty level. So if you want you can
21:39:29
start leveraging this and uh I will be posting the link of this document inside
21:39:34
the description of this video so you can easily check it out from there. Thank you.
21:39:46
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do invert a binary tree lead
21:39:52
code problem. And if we see some of the companies where I want to work at who have already asked this question, there are companies like Amazon, Facebook,
21:39:58
Google, Apple, Bloomberg, Microsoft, Uber, Goldman X and LinkedIn. So that's why I'm paying my utmost attention. I
21:40:04
hope you also enjoy the video. So this is the lead code easy problem
21:40:09
and also very well-liked problem on lead code. Basically we are given the root of a binary tree and we need to invert the
21:40:15
tree and return its root back. So let's try to understand this with couple of example. First of all we'll take this example. So over here we are given a
21:40:22
tree that looks like this where this two uh one and three are part of the tree where one is the left child and three is
21:40:28
the right child. So if we invert this tree we will get an answer that looks like this where two remains the root because it is the root node. But this
21:40:35
three that was originally the right child will become the left child. And this one that was originally the left
21:40:40
child will become right child. And this is what we need to return. Let's take a little bit more complicated example. So
21:40:45
over here we are given the root to be four. Now we are given that the left child and right child of this four is actually two and seven. And further down
21:40:52
we are given more left child and right child for this two and seven as well. Now if we invert those all of them we
21:40:58
will actually get a result that looks like this where four remains the common uh this seven that was originally the
21:41:03
right child will become the left child and this two that was originally the left child will become right child and same thing will happen for these leaf
21:41:09
nodes as well and this is the answer we need to return in the answer. This is what the problem is asking us to do.
21:41:15
Let's see that what would be the different approaches to solve this problem. Before we come up with the optimal solution let's understand a very
21:41:21
important concept. Suppose this is one of the kind of a binary tree we are given and we need to invert this tree.
21:41:26
Well, if we see over here we are given a root node. Then again we are given some left child and we are given a right child. Now further down for this left
21:41:32
child and right child they also have the children of their own and they also form a bigger binary tree. So at any given
21:41:40
moment suppose we are given this root node. We are given this left child and we are given this right child. So if we
21:41:45
want to invert this tree all we have to do is whatever this right child is and
21:41:50
whatever this left child is if we just swap them or if we invert them basically
21:41:55
we are at least done with this root level and with this left child and right child level. Now again if we further
21:42:01
break down that uh suppose this is the left child now we are treating this left child as a root. So suppose now this is
21:42:08
the root and this is the left child and this is the right child for this root. So again if you want to invert them what
21:42:14
we can do is we can take whatever the left sub tree and right sub tree is. So in this case for this root the left sub
21:42:20
tree is going to be this the right sub tree is going to be this. If we swap them uh essentially we have taken care
21:42:26
of up until this level for this uh inverting part and same way we can keep on repeating the process. So now this
21:42:32
becomes our root. Again we flip these two values and even for this level we have taken care of inverting the binary
21:42:39
tree. So this is what exactly I'm suggesting us to do in order to solve this problem that we we starts breaking
21:42:45
this given input into bunch of uh smaller inputs and start inverting binary tree in that manner. So the idea
21:42:52
is that for every single time uh we will have a root node we will swap its left and right child then again for if there
21:43:00
exist any left and right child we will repeat the same process and keep on swapping those values which means that
21:43:06
we are actually doing uh doing the changes recursively recursively we can actually solve this
21:43:12
problem pretty efficiently. Uh let me quickly show you how. Suppose this is the input we are given and we are trying
21:43:18
to invert this binary tree recursively. So what we are going to do is suppose we will take initially this as the root
21:43:23
node and for this root node we actually have a left child and we actually have a right child. So what we are going to do is we are going to swap its values and
21:43:29
we are going to swap the entire left sub tree and entire right sub tree. Then at any given moment as long as we have some
21:43:36
nodes we are going to keep on treating them as different root nodes and then we will keep on flipping their values or
21:43:42
their children's values and at the end we should have a completely inverted binary tree. So let's see that in
21:43:47
action. So first of all this is the root node and this is the left and right sub tree. So what we are going to do is uh
21:43:52
we are going to swap the values. So we will we will have a tree that looks like this.
21:43:58
Okay. So so far treating this as root tree. We have actually swap these left sub tree and right sub tree and we will
21:44:05
get a tree that looks like this where you can see that this value three and two they are actually inverted but their subsequent children values they are not
21:44:11
inverted and we will still have to repeat the same process. So let's see that in action. So now again what we are
21:44:17
going to do is we are going to treat this three to be root child and we are going to repeat the same process with the six and seven. So if we invert them
21:44:24
we will get a tree that looks like this. Now we are going to treat the seven to
21:44:29
be the root node. If we treat the seven to be the root node actually it does not have any children which means we don't need to flip any more values. Now again
21:44:36
we will treat the six to be the root node. If we treat the six to be the root node again it does not have any more children. So we can skip that. Now we
21:44:43
will treat this two to be the root node. So if we treat this two to be the root node, it has children. So we will have to swap their values and we will get a
21:44:50
value that looks like this. And we would have taken care of both of them. Now
21:44:55
again this five and four does not have any children which means we can't do anything about it. And then in the end
21:45:01
this is going to be the answer we need to return. So we can simply return the root value and basically we would have
21:45:06
inverted the entire tree uh recursively. So that is the approach we can use as an optimal solution. There is also one more
21:45:13
way to iteratively approach this problem. But the thing is I believe that for tree kind of problems the iter the
21:45:19
recursive approach is better than the iterative approach. Let me know in the comments if you want to see the iterative approach as well and I can
21:45:25
make a separate video on that. If we see the time and space complexity in this case the time complexity is actually going to be big of n where n is the
21:45:31
number of nodes that are present inside any given tree because we will have to iterate over every single tree to invert
21:45:37
them. Now if we see the space complexity well at any given moment because of the recursive function we might have to uh
21:45:43
store bunch of different node values and that would depend on the height of the tree. So basically the space complexity
21:45:49
is going to be big of h where h is the given height of any binary tree.
21:45:57
So because we are going to solve this problem recursively. First let's uh create the terminating condition that if
21:46:03
the given route is actually null we can return if the given route is not null we
21:46:08
are going to make the recursive call for right and left values.
21:46:13
So for right tree we are going to make the recursive call to the same function with the right child
21:46:19
thing we are going to do for the left sub tree. After that we are going to replace the
21:46:25
values of left and right sub tree. Uh so now that should have taken care of
21:46:30
all the cases and now we can simply return the root value
21:46:35
and that should be it. So let's try to run this code.
21:46:41
Okay, seems like our solution is working as expected. Let's submit this code.
21:46:46
And our solution is actually pretty efficient. It's actually 100% faster than all the other solution. And that is
21:46:51
because the runtime is actually 0 millisecond. I will be posting this in the comments so you can check it out from there. Thank you.
21:47:07
So the lead code problem we are going to solve is called balance binary tree. Now we can see that this one is a lead code
21:47:12
easy problem and also one of the most liked problems on lead code. The problem statement is quite straightforward that
21:47:17
we are given a binary tree and we need to determine that whether it's a height balance binary tree or not. So the
21:47:22
question is what does height balance tree means? It's actually quite straightforward. Height balance tree means that at any given moment the
21:47:30
height of left subree and the height of right subree if they do not difference
21:47:36
more than one. So which means that there is the maximum difference of heights is
21:47:42
like one or zero. If that is the case then we can say that this one is a
21:47:47
height balance binary tree. Okay. Or balance binary tree. But if we identify so let's try to understand in this case
21:47:54
currently this one is our root node. Now if we see the left subree we can see that the height of this left sub tree is
21:48:00
two for the right sub tree the height of this right sub tree is three which means the difference between left and right
21:48:06
subree is not less than or equal to one which means this one is a balanced tree
21:48:13
or like height balance tree. But in the same scenario, let's imagine that if we had one more nodes like this, then the
21:48:20
height of this right side binary tree is going to be four. Meanwhile, this left
21:48:25
sub tree is still going to two. So if we do the difference of the height, we get the answer as two, which is definitely
21:48:30
greater than one. In this case, we can say that now this binary tree is not a
21:48:36
balance uh not a height balance binary tree. Okay. So this is what we need to determine. Now this is like a very
21:48:43
straightforward problem. Basically at any given moment we need to do check
21:48:49
that for any given node what is the height for both left and right sub tree.
21:48:55
And this we can calculate very easily by simply traversing over the given tree in
21:49:00
like any BFS or DFS fashion. And once we do the traversal at any given moment we
21:49:05
will have to keep track that for any particular root node what is the height of its left sub tree? what is the height
21:49:11
of its right sub tree and if the moment we identify that the difference is actually greater than one then we can
21:49:17
clearly say that this is not a balanced tree. If we identify that we iterate over the entire tree and we did not find
21:49:23
that the height to be greater than one at any given moment between left height and right height then in that case we
21:49:29
can say that this one is a balanced tree. So that's it. This is all what we need to do. The approach is quite
21:49:35
straightforward and the idea we are going to use is that we need to traverse over the given binary tree. So for
21:49:42
traversal we know that there are iterative methods and recursive methods. Let's try to do it recursively. So
21:49:47
recursively we are simply going to iterate over the given tree. We need two items for the recursive case. First
21:49:53
recursive condition is the base case. So base case is going to be that if the given current node is equal to null or
21:49:59
zero then we have basically exhausted every single child that we can visit for that particular tree. So we we can do
21:50:06
that what is going to be the recurrence uh call that we need to make at for the recurs recursive level that we are going
21:50:13
to check that for any particular root node first we are going to traverse its left child and then we are going to
21:50:19
traverse its right child. Uh so that is also good. Now while traveling the moment we enter a new height or a new
21:50:26
left child or a new right child we are going to have a counter that is going to keep track of the left height and we are
21:50:33
also going to have a counter that is going to keep track of the right height. We are going to update it uh
21:50:38
sequentially with every single level that we are increasing and during every single update we are simply going to
21:50:44
check that if the difference between left height minus right height and we are going to do an absolute difference.
21:50:50
So uh we don't care about which one is greater as long as the delta is uh greater than one. The moment we find
21:50:57
this one we can say that this one is an invalid or not a proper balance height
21:51:02
balance binary tree. And if we reach to the end we can say that this one is a height balance binary tree and we can
21:51:09
return this answer very easily and very simply. So the approach is quite straightforward. If we see time and
21:51:14
space complexity in this case the time complexity is simply going to be big of n where n is the number of nodes that
21:51:19
are present for the space complexity because we are using recursion we will have to induce or create a new recursive
21:51:25
stack so that might increase the time complexity to big of n and if you try to do this recursively you can also do this
21:51:32
in big of one space complexity as well but I don't think like any interviewer is going to have any issue of you using
21:51:38
recursion because that is a great way to save some time and now let's quickly see the coding solution for this one.
21:51:48
So if you see the solution, it's quite straightforward. We need to get return a boolean answer that whether the given
21:51:53
tree is balanced or not. And in the input, we are given the root. Now first we check for our base case that if the
21:51:59
given root is equal to null, we can simply return true. If that is not the case, we are going to calculate the left
21:52:04
height and we are going to calculate the right height. For that, we are going to use a helper method called get height
21:52:09
and we are going to pass in the root value. Now inside the get height method we are also going to check recursively
21:52:16
that whether if the given node is equal to null we can return zero. If that is not the case we are once again going to
21:52:22
recursive recursively call the same method for the left child and for the right child and at every given instance
21:52:29
we are simply going to calculate the maximum height we have been able to find both for left height and right height
21:52:35
and we are going to add plus one. So this is going to give us the height at any given left subree and right sub tree
21:52:41
that we are going to fetch values over here. Then we are simply going to have our math do.absolute formula that if the
21:52:47
difference is greater than one then we can simply return false. If that is not the case then we simply need to uh say
21:52:54
that yeah if the this given uh true tree is balanced. So that's it. This is the
21:53:01
whole solution. we can simply uh run the code and then I think it should be working fine.
21:53:09
Okay, seems like our solution is working. Okay, let's submit this code
21:53:15
and our code runs 100% faster because there are very few test cases. So this is pretty awesome. Now once again this
21:53:22
whole solution is actually posted on our GitHub repository that you can find over
21:53:27
here. Now this GitHub repository contains hundreds of very popular every
21:53:32
single lead code problem that you can imagine and for each and every problem I have also provided that uh what is the
21:53:40
lead code problem statement for that particular problem what is the Java solution and for some reason if you
21:53:46
cannot understand the solution on your own you can actually go to the video solution as well I have provided the link so this is a great resource for
21:53:53
anyone trying to prepare for lead code or DSA problems. Uh the other thing is I
21:53:58
also want to show you one more resource that I have created or not the lead code one but the document that I have been
21:54:04
able to curating. Now this document contains two very important list. First
21:54:09
list is the most popular and like technical interview questions of all time. Now over here I have created a
21:54:15
list of 130 questions. For each of these 130 questions, I have divided them based
21:54:21
on the topic that you need to prepare and I have also provided the key important information that how many
21:54:28
times that particular question has been asked at what type of company. So this
21:54:33
will help you in couple of ways. Number one, you would be able to understand if you're targeting any specific company.
21:54:39
You can find that how many times that question has been asked at that company. Uh number two based on just looking at
21:54:45
the question you can understand that how important that question in general is. So some questions have been asked like
21:54:51
literally hundreds of times by many top tier companies. So you should be able to identify that as well. And each of the
21:54:57
topics are distributed based on like easy, medium and hard lead code problems. So that is one option. Second
21:55:03
one is the need code 150 list that I'm currently working upon. So this is like
21:55:08
the 150 most asked questions list created by neat code that is an addition
21:55:13
to blind 75. Now this is also a very pretty and very important list. Uh once
21:55:18
again all the questions are based differentiated based on topics. We can also see that uh for most of the
21:55:24
questions I'm trying to go through them and generate solutions for them as well. So yeah uh if you want you can also
21:55:31
check out this resource. Maybe it can be helpful with your prep uh journey. Okay.
21:55:43
Hello friends, we are not employed by a fing company. So let's not stop lead coding till we get there. Today we are going to do binary tree level order
21:55:49
traversal lead code problem and if you see some of the companies where I want to get a job who already asked this question there are companies like
21:55:55
LinkedIn, Amazon, Microsoft, Facebook, Bloomberg, Google, Apple and Uber. So
21:56:00
that's why I'm paying my utmost attention. I hope you also enjoy the video.
21:56:06
So this is a lead code medium problem and basically we are given the root of a binary tree. Now we need to return the
21:56:12
level order traversal for this binary tree and we need to return the nodes values. Now we are also told that we
21:56:18
need to return them in left to right fashion and a level by level. Basically we are given a binary tree over here.
21:56:24
Now for any binary tree basically we always have two things. We have a root node or a parent node and that parent
21:56:30
node has some children nodes. So and furthermore this children node can have children of their own as well. So every
21:56:37
time a new set of nodes are being added at the bottom essentially we can define a new level being created. So if we see
21:56:44
this example over here essentially this is level one this is level two and this is level three. And we need to return
21:56:50
the nodes levelwise from left to right. So let's try to understand this with this example over here where we are
21:56:57
given three levels. So this is level one. These two nodes they are located at level two and this two nodes they are
21:57:02
located at level number three. So in the answer first of all we are going to return this node three because this is
21:57:08
the only node at this level. There are no other nodes. Now at the second second level we have two nodes 9 and 20 and we
21:57:15
need to return them in the same sequence of 9 and 20. And in the third section we have two nodes 15 and seven. First we'll
21:57:21
return 15 and then we will return seven. And that is the answer we are going to return in this case. uh let's see that
21:57:27
what would be different approaches to solve this problem. So when it comes to tree traversals
21:57:33
there are mainly two subcategories. First one is a depth first search and second one is a breadth for search. Well in the depth first search we actually
21:57:40
expand upon the depth of any given tree and then we keep on iterating over all the nodes. While in the breadth search
21:57:46
we actually visit the root node first and then visit its children and then keep on repeating the same process. So
21:57:52
in this portion for depth first search there are three further subcategories in order pre-order and post order which I'm
21:57:58
going to show you first and then I'll explain you how breath search work and in this problem actually we are going to use breath first search to solve this
21:58:04
problem. So during the inorder traversal basically first we visit the left side
21:58:10
of the tree then we v visit the root node and then we visit the right node. So first of all for this root node we
21:58:15
will keep on expanding until the left node exists. So left node exists over here and then left node again exist over
21:58:20
here which means this is the first node we are going to visit. So we start our visit traversal at four. Now four does
21:58:26
not have any more children which means we can't go downwards anymore which means now we go back to the root node.
21:58:31
So root node for this four is actually two and then we again expand on the right side. For this two we still have
21:58:37
right side five that we haven't visited. So we will do that. Now again we have visited all these three nodes. So now we
21:58:43
are done with these. Now we again go back to the root node which is one. So we visit one and then again we repeat
21:58:49
the same process left, root and right. So again we go on the right side. So this is the strategy for in order
21:58:55
traversal. Now for the pre-order traversal basically we follow the principle of root left and right node and this is the
21:59:02
way visited the node. So first of all we are going to visit the root node which is one in this case. Then again we are
21:59:07
going to visit the left node which is two. Then again we are going to visit the left node which is four. Then again we are going to visit the right node
21:59:13
which is five. Again we come back and now in this case we again go back to this root node which is three. Then
21:59:19
again we go to the left and then again we go to the right. So this is the strategy for using a pre-order
21:59:24
traversal. Now for the post order traversal basically we follow the principle of left node, right node and then root
21:59:31
node. So first of all we are going to visit up until left node exists. So this is the leftmost node. So we are going to
21:59:37
visit that first. So we start our browser at this position number four. Then we visit the right node which is
21:59:42
five. And then we visit the root node which is two in this case. Now after this we actually don't visit this node
21:59:48
one because for this road node one there's exist a right sub tree that we haven't visited. So we again go to the
21:59:55
right side and again this also has a left node which is six. So then we visit the node six in this case. Then we visit
22:00:00
the node seven and then for after visiting the six and seven then we visit its root node which is three. And in the
22:00:07
end after visiting all the nodes we visit the main root node which is one. And this is going to be the traversal
22:00:12
strategy for the post order traversal. So when it comes to breath for search,
22:00:18
we actually expand upon its neighbors or its children for any given tree rather
22:00:23
than going in depth in any one particular direction. So if we see for this particular tree the breath for
22:00:29
search traversal is going to look like this. So first of all we are going to visit the root node which is one in this case. Then we are going to visit its
22:00:36
children. So its children are actually two and three. So we are going to visit this node 2 and three. And now for this
22:00:41
left child again it still has children of its own. So we are going to visit them first. So we are going to visit
22:00:47
this node four and five. And then for this node three it has childrens of its own as well which is six and seven. Now
22:00:53
in this case we cannot further expand because this four 5 6 and 7 does not have any children of their own. So we
22:00:59
are done with the traversal. Basically we have iterated over all the nodes that were given. But if you see these nodes
22:01:04
and the fashion we have visited them. It actually gives a very interesting uh perspective for the problem we are
22:01:10
trying to solve. Well, first of all, we are visiting the node that is located at this position number one. Then we
22:01:15
visited its children which are actually located at this level two. So first we visited the level one node. Then we
22:01:21
visited all the nodes that are present at level two. And then we visited all the nodes that were present at level
22:01:27
three. If we had any further nodes then we would have visited them that were for the nodes that were located at this
22:01:34
level number four. So this breath for search is actually a very good solution for the problem we are trying to solve
22:01:40
where we we are trying to see that what would be the level order traversal for any given tree. Basically we are anyways
22:01:47
iterating the nodes in particular levels. So all we will have to do is just simply make tpples of the levels
22:01:54
that we are visiting and the nodes we are visiting at. So that is how we are going to optimally solve this problem.
22:02:04
Now we are going to use the same tree that we have been using so far and we are going to see that what would be the answer. So first of all we will have to
22:02:11
create an array list where we are going to store the answer. Now at any given position whenever we start iterating
22:02:17
over this tree and whenever we jump to a new level we are going to create a new node inside our array list. Uh so first
22:02:23
of all we are at this level one right. So now for this level one we are going to create a new node over here which is
22:02:29
this one. And for this level because this node is located at level one, we are actually going to create an entry
22:02:34
over here. Now for this one, we are actually going to iterate over its children. We are going to call its
22:02:41
children 2 and three. Now with because these are children of this node one,
22:02:46
they are actually going to be located at level which is whatever the level of this one is + one. So the level of this
22:02:54
one is actually one. So 1 + 1 is going to be two. So these nodes they are
22:02:59
actually going to be located at level two. Now the moment we identified a new level we are actually going to create a
22:03:05
new node inside our array list. So over here we would have created this new node. Now in this new node because we
22:03:11
visited these values two and three. We are going to actually add the value two and three over here. Now again we will
22:03:18
have to further go down for this level two and three. And remember that initially we only had this one node and
22:03:25
we visited its children. Now again we have a node and we are visiting its children and again we have a node and we
22:03:31
are visiting its children. And suppose these had if the new nodes we would have visited their children as well. So
22:03:37
basically we are doing the same work for different set of inputs where initially this was a child but now this becomes a
22:03:44
parent for these nodes. So we are basically doing recursion nothing special in this. So now from from this
22:03:51
level two whenever we will call these left and right children basically what we would have done is we would have
22:03:57
increased whatever the value of level was for this value to + one. So this was
22:04:02
located at level two which means these nodes they are actually located at level three. So now again we created a new
22:04:09
level. So because we created a new level, we are going to create a new entry inside our array list. And then
22:04:14
all the values located at this level, we are actually going to store them in this portion of our array list. So now we are
22:04:21
going we are first of all we are going to visit node four. So we are going to add node four over here. Then from this
22:04:26
two we are going to visit its right children which is this node five. So we are going to add five over here. Now we
22:04:32
still have nodes that we haven't visited. So now we have this node three. So we are going to first of all visit
22:04:37
its left children which is this node six and this is also located at level three because this three originally was
22:04:43
located at level two. So this is also because this is at level three we are adding it in the third portion or third
22:04:50
placeholder inside our array list and then in the end we are going to visit this node number seven as well at the
22:04:55
end. Now this does not have any further children. So we are good up until this point and we can stop our traversal and
22:05:01
return this new array list that we have created as the answer. So this is the approach we are suggesting and if we see
22:05:07
we did the breakfast search traversal and basically we did it recursively. Now
22:05:12
we could have done it iteratively as well nothing special in there. Uh so you can discuss with your interviewer what
22:05:17
is the strategy you want to use and nine out of 10 times your interviewer is going to ask you to do this problem recursively because it's lot lot less
22:05:24
code. Uh if we see time and space complexity in this case the time complexity is actually going to be big of n where n is the number of nodes that
22:05:31
are present inside this given node. And if we see space complexity well uh basically we will have to create
22:05:38
recursive we will have to make recursive calls and that takes uh some space and that space is actually dependent on
22:05:44
height of the given tree. So space complexity is actually going to be big of h where h is the height of the tree.
22:05:53
Now first of all we are actually going to create a list of list where we are going to store the answer and we are
22:05:59
going to declare it as a global variable because we are going to create a new method for our recursive call. So first
22:06:06
of all let me create this global variable called answer. Now we are going to create a new public method which is
22:06:13
going to be uh acting as our recursive function and it does not return anything. We are going to name it as
22:06:18
order and as an argument it is going to take any tree node and the level we are
22:06:24
currently at. And now inside this method first of all what we are going to do is
22:06:29
that whenever we are at any position or whenever we are creating a new node basically we are going to add a new
22:06:35
entry to our answer. after creating a new value for a new level. Now all we
22:06:40
will have to do is whatever this three node is based on its level value we will have to add that value to our answer.
22:06:47
Now after doing that basically all we will have to do is for any single given node value first of all we are going to
22:06:52
check that whether it's left child and right child if they exist or not. If they exist basically we are going to
22:06:57
call the same order method with this left child and right child and we are going to increase the value of the
22:07:03
levels. That is all we need to do for this order meth. So now from this main method first
22:07:09
of all we are going to check for an edge case that if this given route is null. If this is null we can simply return the
22:07:14
answer. And if this given route is not null
22:07:20
basically we will have to call this order method with our root information and the current level that we are at.
22:07:27
And now at the end we simply have to return whatever the answer we get. Let's try to run this code. It seems like our
22:07:34
solution is working as expected. Let's submit this code.
22:07:39
And our code is actually pretty efficient compared to a lot of other solution. And I would be posting this in the comments so you can check it out
22:07:45
from there. Thank you.
22:07:53
Lead code problem we are going to explain is going to be binary tree zigzag level order traversal. This is a
22:07:59
really popular problem and this has been asked in some of the top tier companies such as Amazon, Bloomberg, Microsoft,
22:08:05
Facebook, Apple, LinkedIn, Google, Samsung, Goldman Sachs and Tik Tok. So
22:08:11
that is why I'm paying my utmost attention. I highly urge you to pay your attention for this problem as well. If
22:08:17
we see that this is a lead code medium problem and also very well-like problem. Now in this problem we are given the
22:08:23
root of a binary tree which means a binary tree means that any single parent can have at most two children nothing
22:08:29
more than that. So no so now we have the root of this binary tree and now we need
22:08:35
to return the zigzag level order traversal from its nodes values. So what
22:08:41
does a zigzag level order traversal means? So first of all before understanding the zigzag level order
22:08:46
traversal let's understand what does a level order traversal means? Level order traversal simply means that first we go
22:08:53
through the first level that is level zero then level one then level two. So
22:08:59
if we see the level order traversal first we would it go through value number three then second level so that
22:09:05
is value number 9 and 20 and then uh the third level that is 15 and 7. But since
22:09:11
in this case the level order traversal that we were making was pretty simple.
22:09:16
We were going from left to right. So we went from here we went to left to right
22:09:22
again from here we went from left to right but in this case we are making our lives easier and we are going in the
22:09:28
zigzag fashion because that is the current trend and zigzag fashion is that first we start over here from left to
22:09:36
right from the root node then we go in the zigzag fashion. So we go like this,
22:09:42
like this. And now again we repeat the zigzag pattern. And now we go from left
22:09:48
to right again. So for one level we go from left to right. Next uh level we go
22:09:55
from right to left. And again next level we go from left to right and we keep on repeating the same process. So in this
22:10:02
example if you see first we went through level three left to right. This was the
22:10:08
value. Second we went through the right to left. So 20 and 9. So from after
22:10:15
three we visited 20 and 9. And then we went through 15 and 7. 15 and 7. And
22:10:24
let's see what would be the solution for this problem. Okay. Suppose this is the input we are given. Now first let's see
22:10:30
what is the level order traversal going to be. First we are going to visit value number one. Then we are going to visit
22:10:36
in this fashion. So the value is going to be 3 and 2. Then again from this fashion. So value is going to be 4 5 6.
22:10:43
And then again from this fashion. So the 8 and 7. This is going to be the answer
22:10:48
for sure. We already know that. But how we are going to come up with the answer.
22:10:54
In order to come up with the zigzag level, first we need to go through the simple level. How to go through simple
22:11:00
level order traversal? Well, what what we are doing in a simple level order traversal is that we are iterating the
22:11:07
parent then we are iterating its child before iterating its grandchild. So in
22:11:13
this case first we are going to it we are this place we are going to uh
22:11:18
iterate over its child. After iterating both children we are going to iterate
22:11:24
its grandchildren or the children of these children. So first we would be
22:11:29
covering this level. Then after covering this level, we would be going through the children of these nodes. So going in
22:11:35
this fashion and again repeating the same process with this one and this can
22:11:41
be achieved using breath first search because it's pretty simple to do and this is how breath how traversal in done
22:11:48
is done in trees using breath first search that that is a level order traversal. So even in this case we are
22:11:54
going to use the breath first search to run in a simple level. But how do we use
22:12:00
breath for search? Well, from our experience, we know that in order to use breath for search, we need two items. We
22:12:06
need a cube and we need a visited hashet. But the thing is we only need visited hashet in a graph kind of a
22:12:13
problem where there is an issue of us running in an infinite loop. There is no issue of us running in an infinite loop
22:12:20
inside a tree. So we are not concerned about using a graph in this case. We are only going to use a cube. And currently
22:12:26
I'm just showing you how to do a level order traversal and then we will do zigzag level order traversal. So first
22:12:33
let's just see the level order traversal. For that we are first of all going to start at the root position and
22:12:39
we are going to populate that value inside our cube. So this is currently value number one. Now we are going to
22:12:46
visit the children of one before visiting the grandchildren of one. This is the whole logic of the BFS that we
22:12:52
are going to visit the children before visiting the grandchildren. So who are the children? Obviously two and three.
22:12:59
Again we are going to add values two and three here because it has two children and we are going to mark them. Now we
22:13:07
visited all the children of value number one. So we are going to pop value number one out and we are going to put it in
22:13:14
the answer that we traverse this part already and now we only have values 2 and three inside the input. Now again
22:13:21
for two and three uh two has children that we haven't iterated over. So who
22:13:26
are the children of two? Four and five mark them here and same way get uh get
22:13:32
rid of two. So two has been taken out and now currently the entries are 3, four and five inside our queue. 3 4 and
22:13:40
1 again. Three can be kicked out by adding six at the end of the queue. We
22:13:45
added six at the end of the queue. Awesome. Now three is also out. Currently the entries are four, five and
22:13:51
six. Now even for the values four, five and six starting at position number four. It does not have any child. So
22:13:57
four can be kicked out without any repercussion. Five currently has a child seven. So adding seven at the end and
22:14:04
getting rid of five. Uh so we can put five over here. Again values are six and
22:14:11
seven in place. Again for value number six it has a child called 8. Adding 8 in
22:14:17
the end and getting rid of six. And now after that it there are only two values left seven and 8. Currently seven does
22:14:24
not have a child so we can get seven out. And also 8 does not have a child. So we can also get eight out. And this
22:14:30
would be the solution. But in this problem what we did is we went in the uh
22:14:35
normal level order traversal not the zigzag level order traversal. So let's see how can we make zigzag level order
22:14:43
traversal possible. Currently what the concept we are using inside the queue is currently we are using the first in
22:14:50
first out principle that gave us the level order traversal. But what happens
22:14:56
is that when we move from left to right this concept is absolutely true that we
22:15:03
can get we can have like first in first out and that would give us the proper level order traversal. But when it comes
22:15:10
to reversing, imagine that in this case rather than
22:15:16
getting two since two was already inside the loop before value number three. If
22:15:23
we pop three out before two, then we would have been able to accomplish our mission. So since in this case we are
22:15:31
going in the zigzag fashion. Remember zigzag fashion is going to be like this where one and on one iteration we are
22:15:38
moving from left to right. Next iteration we are moving from right to left and again for the next iteration
22:15:45
iteration we would move from left to right and we would keep on repeating in
22:15:50
the alternate fashion till we reach to the or to all the nodes inside the given input. So now let's see that what are
22:15:57
some of the adjustments we can make to make our lives so much more easier and
22:16:02
fix this issue that we were having uh in the level order traversal. The solution
22:16:08
is quite simple and the solution is that whenever we have to find from left to
22:16:13
right we can use the concept of first in first out. So this first in first out is
22:16:19
going to use on these two occasions. But when we need to move in the reverse
22:16:25
order or right to left in this case we will have to use the concept of last in first out because logically what was
22:16:33
happening in this case is that logically we were traversing in last in uh sorry
22:16:38
left to right for every single one of them in the level order traversal. So typically we were going like 2 and three
22:16:45
but imagine since three was last added if we took the last and first to
22:16:50
approach then inside the solution we would have values such as this one. So one is following FIFO first in first
22:16:58
out. So one was added first and one was removed first. But for this particular
22:17:04
position we are using the concept of last and first out. So even though two
22:17:09
was in the queue before value number three, we are going to have three that
22:17:15
was the last value come out before the value of two. So 1 3 and 2 such like
22:17:21
this. Again we are going to use first in first out for this particular uh level. So the solution is going to be 4 5 6
22:17:28
that is pretty simple. But for these two again we are going to use leo principle
22:17:34
and that is going to give us the answer of 8 and 7. Now if we see this sequence
22:17:40
1 3 2 4 5 6 8 7 this matches with the original answer we wrote at the
22:17:46
beginning 1 32 45 6 87 and this is the whole solution. So let me clean this up
22:17:52
a bit, walk you through my solution where we are simply arranging the way we
22:17:58
are entering the values inside the key uh inside the queue and popping the value out of the que. Okay. So now we
22:18:04
are going to have our cube. We are going to add all the entries and the only simple thing we are going to do is
22:18:11
whenever we have to move from right to left, we are going to pop the value at the from the end of the queue rather
22:18:18
than popping from the beginning of the cube because we are flipping between FIFO and LEO principle. And the one data
22:18:27
structure that is capable to do this is actually a dq data structure uh in like
22:18:33
both Java and Python languages. So you can use either one of them. Okay. So let's start iterating starting from
22:18:40
value number one. One is placed here. Currently one has two child two and three. So we are going to mark two and
22:18:46
three in this position. Currently for one we are iterating from left to right. So we are going to get the last in first
22:18:53
out. So one would come out. Now the values are located as 2 and three. Even
22:18:58
for two and three currently we need to get them out in the zigzag fashion or right to left fashion. So for that first
22:19:06
we are going to pop it from the end. But before popping it from the end we will
22:19:11
first add the children of two and three. So the child of two is four five. So let's add four five here. And child of
22:19:18
three is six. Let's add six here. After doing that we are going to pop three out
22:19:23
first and then we are going to pop two out first. So three and two has been out
22:19:28
because three was value before two and again for 4 5 6 we need to do the same
22:19:34
thing but we need to do in the left to right fashion. So 4 5 6 are going to come out as they as themselves but
22:19:41
before that we are going to iterate through it their children. So four currently does not have a child. So we
22:19:46
can pop it out without any repercussion. But five has a child the value is seven.
22:19:52
And six has a child the value is eight. Again we pop five out. So popping five
22:19:57
out should be simple. And popping six out should be simple as well because we
22:20:02
already took care of them. But for value 7 and 8 again we are moving in the right to left direction. So last in value 8 is
22:20:09
going to come out first before seven coming out. And in the end we would not have any values inside our cube which
22:20:16
means we can get rid of it. And now you see the traversal is being done in the
22:20:21
level order and also in the zigzag fashion. And that is the most important
22:20:27
fact. And this is how you solve this problem. Again if we try to see the time and space complexity the time complexity
22:20:33
is going to be bigo of V plus E or vertices plus edges or nodes plus edges
22:20:39
because we are using our BFS and space complexity since in order to use the BFS
22:20:44
we will have to use a cube the space complexity is going to be bigo of V or the number of nodes or number of
22:20:52
vertices inside our given tree. And this is the whole solution. Let's see the coding solution for binary tree zigzag
22:20:59
level order traversal. So first of all for this one we are given the method
22:21:05
that to return a list of list uh that contains the zigzag level order traversal of the given input uh tree and
22:21:12
as a input we are given the root node. So first of all we are going to check for the edge case that if the given root
22:21:18
node is null we can return an empty new array list immediately. If that is not the case, first we are going to
22:21:24
initialize the array list inside this array list. First for the first node, we are going to add the add the root node
22:21:31
and we are going to add a null node as well. And we are also going to use a new
22:21:37
tree node link list to iterate over the given input tree. Now we are going to
22:21:43
mark the level list because every single level contain is going to contain a different set of answers and we are
22:21:51
going to use this boolean parameter to keep track that whether we need to traverse from left to right or right to
22:21:57
left. So is order left is initially set to true which means currently at the
22:22:03
beginning we are moving from left to right. Uh now inside the while loop we are going to do our BFS function where
22:22:11
if this given boolean is order left is true which means we are going to use the
22:22:17
last in first out and add add all the elements inside the level. If that is
22:22:23
not the case then we are going to use the first in first out and also add all
22:22:29
the values that are present on that particular level. After adding all the levels, we are simply going to populate
22:22:35
our result list based on the level list we have created. And then we are going to initialize a new level list for the
22:22:43
next level. And again we are going to change the ordering from left to right
22:22:48
to right to left for the next level. And after repeating the same process again even for the next level the ordering is
22:22:55
going to be again left to right. In the end after this BFS operation doing loop
22:23:01
ends we would have our result link list populated and we would be able to return
22:23:07
that as the answer. So let's try to run the code. Seems like our solution is working as
22:23:12
expected. Let's submit the code. And our code runs pretty efficiently compared to lot of other solutions. And
22:23:19
don't worry I'm going to post the solution of this code inside my GitHub repository that is open to public. So
22:23:25
everyone would be able to see that.
22:23:40
So the lead code problem we are going to solve is called binary tree right side of view. Now we can see that this one is
22:23:45
a lead code medium problem and also an extremely well-like problem on lead code. The problem statement is actually
22:23:51
quite straightforward. We are given the root of a binary tree. Now we need to imagine that as if we are standing on
22:23:57
the right side of the binary tree and then we need to return the values that we see uh from the right side and we
22:24:04
need to return the top to bottom values. So let's try to understand this problem. Currently we have a binary tree over
22:24:10
here. Now imagine yourself that as if you are standing on the right side of the binary tree. So from the right side
22:24:16
of the binary tree you can see only this portion of this given binary tree which
22:24:22
means currently you are only looking at these four nodes and all of because this
22:24:28
node is cover being blocked because of this one and these two nodes are also being blocked by because of this one.
22:24:34
Okay. So in this case what is your right side view or your right side vision of
22:24:40
this tree? Well first you need to return the answer in top to bottom manner. So first we are seeing node number one.
22:24:47
Next we are seeing node number three. Next we are seeing node number six. And lastly we are seeing node number seven.
22:24:53
And this is what we need to return as part of the answer. Now let's first try to understand that what the answer looks
22:24:59
like in each of these three different scenarios. So we have a clear understanding on what is being expected
22:25:04
from um from our side. So if we take a look at this first tree well the answer is going to include this is going to be
22:25:10
the first node. This is going to be the second node. This node would be blocked. So we would not be able to see it. And
22:25:15
then once again this node would also be blocked. So we will include this node. So these are the three nodes that we are
22:25:21
dealing with. Okay. Next uh in this particular scenario we can see that we need to return the right side view. But
22:25:27
thing is hey there is no node on the right side of the tree. So well in that case we can still see the left side of
22:25:34
the uh node as well. So we are going to include this node and we are also going to include this node in our answer.
22:25:40
Okay. And in the lastly this scenario is slightly tricky. So of course this node
22:25:46
is going to be part of the answer. But then at this particular level we will have to include this node. Once again at
22:25:53
this particular level this one is the right child and this one is the live left child. But still because we are
22:25:59
standing on the right side we need to take the value that is closest to us on
22:26:05
that particular level. So once again this node and then lastly on this last level we don't have any particular
22:26:12
nodes. So we are going to use this node. Now in each of these three scenarios we
22:26:18
can see one very clear distinction in terms of answer that is we are seeing
22:26:24
that at any given level we will have to take one node from that particular level. We are going to select the node
22:26:30
that is the last node in that particular level. That is the same case for this one because this is one level. There is
22:26:37
only one node. So this is the last node. Over here we have two nodes but we are only going to consider the last node.
22:26:42
Once again we are only going to consider the last node over here as well. This one there is no explanation needed. This
22:26:48
one is slightly trickier example where we can. Okay. So this one we understood why we take it amongst these two nodes.
22:26:55
We are closest to this one. So we are taking it amongst these two node. Even though these nodes are close to each
22:27:00
other, we are once again closest to the right side node. So we are going to take it as part of the answer. And this one
22:27:06
once again is still the last node at that particular level. So we are able to establish that for any particular binary
22:27:14
tree the right side of the view is simply going to be doing the level order
22:27:19
traversal and finding that the what is the last node at that particular level.
22:27:25
So in e either case we simply have to do a level order traversal. Now level order
22:27:30
traversal for trees typically refers as breath first search. So we know how to do breath first search. It's a very
22:27:36
common and popular um tree traversal techniques. If you don't know what breath first search is let me just
22:27:43
quickly explain. We are at the root position. So what we are going to do is for root position we are going to put it
22:27:49
inside a que. Now we know the property of a Q that it is a first in first out
22:27:54
type of scenario. For each level we are going to iterate over all of the children that it has and if it has the
22:28:00
children we are going to put them on the queue as well and once again repeatedly we are going to keep on subsequently
22:28:06
doing the same thing with their children as well. So logically we would be iterating over in one particular level
22:28:12
by level across the entire tree and that is called breath first search. So let's try to see our solution in action. So in
22:28:20
this case let me give values to these particular nodes and we know that the answer in this case is going to be 1 3 6
22:28:27
and 7. But currently let's say that this is our cube. Now in our Q we are going
22:28:32
to keep track of two things. Number one that what is going to be the last element at any particular node and
22:28:39
number two that uh for every single level we will have to keep track of that
22:28:44
at what level these particular nodes belong to. Okay. So we can very easily
22:28:50
track that because every time we add a new child we can just mark it as like a new new level that we are adding inside
22:28:57
the queue and apart from that we can simply move forward as it is. So currently the first value is going to be
22:29:02
node number one. For node number one because it has children so we are going to add node number two and node number
22:29:08
three inside our array as well uh inside our queue as well. Once again for both
22:29:14
node number two and three they also have the children of their own. So for node number two they have four and five. So
22:29:19
we are going to add four and five. For node number three they have six. So we are going to add six. And lastly we are
22:29:26
going to have uh value number seven that is the child of node number six. So once
22:29:31
again I'm let me just add one more entry over here seven. So now we can see that I have colorcoded every single different
22:29:39
level uh based on all the elements for that particular level. And uh in that
22:29:46
particular color-coded pattern we need to find the last element. So this is basically going to be by default last
22:29:52
element. So we are going to add this to our answer. Next we have two values at
22:29:58
that this particular level. So we are going to pop this element out because we don't care. This is the last element. So
22:30:03
once again we are going to add that to our answer. Once again we have three elements over here. We are going to pop
22:30:08
each one of out. And the moment we reach to the last element we are also going to mark it as the answer. And then this is
22:30:14
also the last element at this particular level. So once again we are going to mark it as the answer. And that's it.
22:30:19
This is the whole solution. Now at first glance it looks complicated but all we
22:30:25
are doing is just doing the breath first search in a common fashion and trying to find the the answer. Now in this case
22:30:32
since we are standing on the right side of the binary tree we are selecting the last element. But same can be said that
22:30:38
if we are given a question where we need to find that what is going to be the left side view where you are standing on
22:30:44
the left side of the binary tree same logic is going to apply. The only thing is now you are going to be dealing with
22:30:50
the first entry that pops up inside of your queue for every single new level
22:30:55
and that is what you need to put it in the answer. So basically these are like two questions in just one question by
22:31:01
just changing the direction of where you are standing. If you see time complexity in this case, this is going to be big of
22:31:07
n. If you see space complexity, this is also going to be big of n because we are using an extra uh extra cube to keep
22:31:14
track of all the elements that we have iterated so far. Uh overall, this is like a decent time in space complexity
22:31:19
because this you have to go through this in any of your tree programs. Uh unless it's a binary tree and you're trying to
22:31:25
search an element. So now let's quickly see the coding solution for this one.
22:31:34
Okay, so this is the coding solution. First, we are going to initialize our new array list to store the answer and
22:31:40
we are going to name mark it as result. We are also going to check for an edge case that if the given root is equal to null, we can simply return the result.
22:31:46
If that is not the case, we are going to initialize our Q and inside our Q, we are going to populate the very first
22:31:54
element that is going to be the root node. Now we are going to iterate over the tree in the breath for search manner
22:32:00
by stating that while Q is not empty do this. So first we are going to define that what is the current size of the
22:32:07
given cube. Then we are simply going to have a for loop to run over the given que where we are going to keep on
22:32:15
pulling elements at every single position and we are going to mark the
22:32:20
last node of the current level inside the result that we are we are going to
22:32:26
populate. Okay. Then we are going to check that for this particular given root value do we have any left child and
22:32:31
do we have any right child. If we do add the left child and right child to the current queue as well and this is going
22:32:38
to iterate over uh the entire binary tree in bre search manner and we would have our result array list populated as
22:32:45
well. In the end we can simply return results and this is the whole solution. So let's try to run the code.
22:32:54
Okay, seems like our solution is working as expected. Let's submit this code and our code runs pretty fast compared
22:33:00
to lot of other solutions. uh few things can be improved in terms of uh space complexity but anyways this is a good
22:33:07
enough solution. I would be posting this in the GitHub repository that we have created.
22:33:21
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do sub tree of another tree
22:33:28
lead code problem. And if we see some of the companies where I want to get a job who have already asked this question, there are companies like Amazon,
22:33:34
Microsoft, Google, Facebook, Apple, Bloomberg and Tesla. So that's why I'm
22:33:39
paying my utmost attention. I hope you also enjoy the video. So this is a lead code easy problem and
22:33:45
basically we are given the roots of two different binary trees called root and subroot. Now we need to check that whe
22:33:52
whether there exist a sub tree of this original root tree where the structure is completely same as whatever the sub
22:34:00
root binary tree that we are given. If that is the case we will return true. If that is not the case we will return
22:34:05
false. So let's try to understand this with an example. Basically we are given two different binary trees called root
22:34:11
and subroot. Now over here we can see that the structure of the subroot which
22:34:17
contains the root value as four. left child as one and right child right child as two where one and two does not have
22:34:22
any more children of their own. The same structure is also present in this example as well. Uh and because it is a
22:34:30
subree of this original root binary tree, we can return true in this case. Now let's take one more example to make
22:34:36
things a little bit more clear. So in this second example, we are also given two different binary trees. Now if we
22:34:42
see the structure of the sub route, we have a node four. It has a left child and right child of one and two
22:34:48
respectively and they don't have any more children of their own. Now if we see this original root we can also see a
22:34:55
similar structure and I'm focusing on the word of similar not exact same because in this case we also have four 1
22:35:01
and two present but the thing is notice that this two actually has another node or another left child zero that is
22:35:07
present over here which is not the case in this scenario. So because this is not the case we cannot say that these two
22:35:14
are same and these two are actually not same. So in this case we will return false. And basically we are trying to see that whether one tree is a sub tree
22:35:21
of another tree or not. So that's why uh the name of the problem is subree of another tree. It is self-explanatory.
22:35:27
And now let's see what are the different approaches to solve this problem.
22:35:32
So this is the root and subroot we are given. Now over here we are trying to see that what would be the optimal
22:35:38
solution for this problem. And basically we can clearly see that uh the answer in this case is going to be true because
22:35:44
this 9 1 and 2 is also present as a sub tree in this original root tree. So that's why we we can return true in this
22:35:50
case. The thing is let's see that what is going to be the strategy. Well the idea is we are actually going to iterate over this given root tree in BFS
22:35:57
fashion. Now if you don't know what BFS is, BFS is basically breath first search and you can see more details about that
22:36:04
in this video I have done previously. Now uh let's focus on the problem at hand. So the idea is that at every
22:36:10
single time we are going to iterate over this root node and we are going to iterate in BFS fashion which means we
22:36:15
are also going to iterate its neighbors for every single node. Now at every single time we are going to compare it
22:36:20
with this subroot tree and the moment we find a match we are going to iterate over both the trees in BFS fashion. So
22:36:27
let me quickly show you what I mean by that. So first of all uh in this root tree we are I'm going to iterate over
22:36:32
this root number five. Now this root number five is not same as this root number nine. So which means I can't do
22:36:38
anything over here. I have already iterated this value. Now I'm going to iterate its children. So first of all I'm going to iterate over this root
22:36:44
value 8. So this 8 is again not same as this 9. So we can ignore this case. Now
22:36:50
we are at this position number nine. So this 9 is actually same as this 9. So because these two values are same. Now
22:36:56
I'm going to do BFS traversal for both of the subroot and root trees. Now from
22:37:01
this 9 if I see the BFS traversal basically I'm going to go to the left child. So left child in this case is
22:37:07
one. So again I'm going to see the same thing. Even in this case the left child is also one. So yeah I'm good up until
22:37:13
this point. Now I'm going to go to the right child. This is two and the right child in this case is also two. So yeah
22:37:18
again I'm good until this point. Now I'm not going to stop my traversal. I'm going to keep on iterating till I find
22:37:24
all the null values. So in this case this one does not have any children left or right. So in this case I'll encounter
22:37:30
a null value. So I'll try to see the same thing over here. So over here this does not contain any sub child of its
22:37:36
own as well. So this is also null. So I'm good up until this point. Now if I try to see this portion. So this also
22:37:42
this is also null and this is also null. So because all the values are same and I found no other children that I can
22:37:48
iterate over. In this case I can simply return true. Now uh there are two ways to do this problem. Uh I can do it
22:37:54
iteratively or I can do it recursively. And uh if you know my videos I like the recursive method better. So I'm going to
22:38:00
show you the recursive solution. Now let's see one more case where uh the answer is going to be the false. So
22:38:06
suppose for the same example we do everything right but over here this two actually has a subchild called uh let's
22:38:13
just say seven over here. Now uh because this two has a subchild called seven.
22:38:18
Now the moment I am done iterating these values and I don't find anything I'm good up until this point. But now at
22:38:25
this portion at this node two I'll find a value seven over here. But when I try
22:38:31
to find the same value over here, I won't be able to find. And because I won't be able to find, I'll return false. Now the time complexity is
22:38:37
actually going to be go of m + n. Why m + n? Because we will have to iterate
22:38:42
over all the nodes that are present inside this given tree root and sub root. And m is the number of length of
22:38:48
all the nodes that are present over here. And n is the number of length of all the nodes that are present in this
22:38:53
subroot. And if we see space complexity well basically because we are doing it recursively we might have to iterate
22:39:00
over all the values and the space complexity in the worst case could be m plus n as well. And uh now let's move on
22:39:06
to the coding. So before we start working on a sub tree
22:39:13
method, first of all, we are actually going to have to create a new method where if we pass in the value of any
22:39:19
root node and subroot node, it can determine that whether both values are same or not. So first let's do that.
22:39:26
So we created an is same method which takes in the value of two tree nodes.
22:39:31
Now first of all we are going to check that if both values are null which would be the terminating case for our recursive call. So if both values are
22:39:38
null we can simply return true. Now if that is not the case we'll also have to check the scenario where one value is
22:39:44
null and other value is not null. If that is the case we will have to return false. Now there is also one more thing
22:39:50
we'll have to check that and that is the value of this s and t. So if the value
22:39:55
of s and t if they are not the same we can return false immediately and if everything is not uh returned by this
22:40:02
point which means that the value of s and t is same. So now we will have to check the left sub tree of S and left
22:40:08
subree of T. And same thing we'll have to do for the right sub tree of S and right sub tree of T. So let's do that.
22:40:16
Now from our main method is subree method. First of all, we are going to check that if the given root is null. If
22:40:22
that is the case, we can return false immediately. So if that is not the case, we will have to call our is same method
22:40:28
for this root node and subroot node. So let's do that. And if we get the answer to be true, we can return true
22:40:34
immediately. Okay. So if this does not return true, which means this current root and sub route they are not the
22:40:40
same. If they are not the same, we will have to iterate over this node root for its left child and right child to see if
22:40:45
they are same with the sub route or not. So let's do that. So now for that we
22:40:50
will have to call this is subtree method again and we are going to run bfs on this tree node root. Let's try to run
22:40:58
this code. Okay, seems like our solution is working. Let's try to submit this code.
22:41:07
Our submission failed. Let's try to diag. Oh. Oh, and this is
22:41:13
same method. We will have to check that whether the answer of both of them if that is true or not. So, we'll have to
22:41:19
use condition. Let's try to run the code again. Okay, seems like this is working. Let's submit this code again. Okay, and
22:41:26
now our code runs perfectly fine. It's faster than lot of other solutions and I will be posting this in the comments so
22:41:32
you can check it out from there. Thank you.
22:41:44
The problem statement is called count good nodes in a binary tree. We can see that this one is a relatively new
22:41:50
problem, a medium problem and also a very well-like problem. On top of it, this has been asked at tons of different
22:41:56
companies. So let's pay uh some attention that what the question is asking us us to solve. Basically we are
22:42:02
given the root of a binary tree and we need to return the number of good nodes in a binary tree. The question is what
22:42:09
the heck is a good node? Well a tree node is deemed good if in the path from
22:42:16
root to that particular tree node x there are no nodes with value greater
22:42:21
than x. If that is the case that node is a good node. So let's try to understand
22:42:27
this with an example. Currently we have we can see that there are five different node or six different nodes in this
22:42:33
particular tree. Now we are being told we need to find the good nodes. Uh the
22:42:38
definition of a good node is that path from root to any particular node if that
22:42:45
particular node is contains the maximum value then it is deemed good node. So let's try to see what are the good
22:42:51
nodes. Starting with the root. Now root in itself is a good node because path from root to root root is the biggest
22:42:58
value. So we find one good node. Okay. Now let's consider value number one.
22:43:04
What is the path between root to value number one? This path is one the largest
22:43:09
number on this path. No. Which means one is not the not a good node. Then let's
22:43:15
consider the path six. So for six the path is five then one and then six. So
22:43:22
in this case six is the largest number from the direct path through the root which means six is also a good node. So
22:43:28
let's mark that once again. Now we found everything we could. Let's try to move
22:43:34
to next value number five. So is five a good node? Yes, five is also good node. Why? Because the definition of five is
22:43:41
that from root to that particular x there are no nodes with value greater
22:43:47
than x. So in this case the nodes we have is value number five 1 and five. So there are no other nodes that has value
22:43:54
greater than five which means five is still a good node. So we will also mark this as good. Then we will jump to value
22:44:01
number seven. So once again the direct path from five to 7 is this one. So in
22:44:06
this case 7 is the largest node. So 7 is also a good node. And next value is once again seven. So once again even in this
22:44:14
path 5 7 and 7 there are no values greater than this seven as well. So
22:44:19
seven is also a good node. So in this case in total we found 1 2 3 4 and five
22:44:26
good nodes amongst these six nodes. So we need to return five as the answer. And this is what the problem statement
22:44:32
is asking us to solve. So now let's try to understand the logic on the solution
22:44:38
we can build for this particular problem. The logic is quite straightforward that we need to iterate
22:44:44
over the given tree in some fashion and we will have to keep track that around this iteration what has been the largest
22:44:52
value we have been able to find so far keep track of it and using that particular value we are going to make
22:44:58
some important judgment calls. So the logic we are going to do is that we will have to iterate the given tree in depth
22:45:04
for search fashion. Why depth? because we will have to keep track of of the entire path from root to any particular
22:45:11
node. So for that we will have to go into the depth first search order. Now what are the considerations? Number one
22:45:18
thing is first we are going to check the root or at any given position because first we are checking the root then we
22:45:24
are checking for its left uh entire subree and then right entire subree. Same thing we are doing at every single
22:45:31
level that first we are checking that for this particular root whether it is the largest number. After understanding
22:45:36
this, we are checking its left sub tree and then right sub tree. So basically we are doing the pre-order traversal in
22:45:44
this case and pre-order traversal is quite straightforward. The logic is root then left and then right sub tree. So we
22:45:51
are once again going to do a pre-order traversal in this case in depth for search fashion. We are going to keep
22:45:56
track that what has been the maximum value we have been able to find inside the current path. if the current node is
22:46:05
uh equal to or greater than the maximum value we have been able to find. So in
22:46:10
this case we are going to deem this node as a good node. So we are als we also need a variable to store the good node
22:46:16
as well. So let's assume that okay we are going to have our count variable to store all the good nodes we have been
22:46:22
able to find so far and this is the whole solution we need to create. So let's try to understand or let's try to
22:46:30
iterate over our given solution and let's just arbitrarily give some values to these particular trees or these
22:46:37
particular values. So in this case we can see that uh these are the different values. Now let's start with value
22:46:44
number three. Three in itself is a good node because we are doing the depth for search pre-order traversal. We are going
22:46:49
to take care of the root first. Okay. Now we took care of this root. Now let's take care of the left child. So left
22:46:56
child is once again one. So once again even at the left child position we will have to follow this uh position of root
22:47:03
left and right. So once again uh now left child in itself is a root. So we
22:47:08
have value number one. What has been the and also we have our maximum value we have been able to find on the current path. So maximum value so far has been
22:47:15
three. This value is one. So current node is not greater than maximum value which means this is not a good node. Now
22:47:22
we will need to check for the left pointer. So left pointer is once again three. So three is same as the maximum
22:47:28
value on this path we have been a able to identify. So we are going to mark this three as the answer that we have
22:47:34
been able to find so far. Now uh three is also going to be a good node. So we are going to add our count of good
22:47:40
nodes. Now we are going to do a backtrack. Now for the backtracking once again we have a right node that we
22:47:47
haven't checked. So we are going to take care of the right node as well. The value of the right node is five. So currently at this particular position
22:47:54
the right node is actually greater than the maximum value we have been able to identify. So we are going to store once
22:48:00
again count this five as a good node as well. Apart from doing that we will also have to update the maximum value we have
22:48:06
been able to identify. But this particular node does not have any subsequent child nodes of his own. So
22:48:13
because it does not have any child node there is no point in updating the value of the maximum node. But say for an
22:48:19
example if we did had one more child like this uh where we need to check for
22:48:24
the value of this node number six then this five would have been the maximum value we have been able to identify so
22:48:30
far but that is not the case. Once again coming back now we took care of five and
22:48:35
we took care of three. It does not have any children. We are going to do the backtrack. We already took care of one which means now we have to taken care of
22:48:41
this entire left child. Once again in our pre-order traversal uh we took care
22:48:47
of the root very first. Then we took care of the left child. So this is the entire left child portion of this route.
22:48:52
Now we need to take care of the right child. So once again we are going to do the same thing. We are at position number four. So we are going to first
22:48:59
check that whether four is a good node or not. So in this path the current maximum value we have been able to
22:49:04
identified was value number three. So four is a good node. But in this case because we are checking for the
22:49:11
subsequent children of four. So we'll have to update the maximum value we have been able to identify along this path to
22:49:17
value number four. So this is the maximum value we have found so far. Next value is value number two. So two is not
22:49:25
is less than the maximum value we found. So two is not a good node. So in this case we found in total four good nodes.
22:49:31
So we are going to return four as the answer. And that's it. This is the whole solution that we need to return.
22:49:37
Basically we need to understand that why we need to use DFS in this case because we are going in one particular
22:49:43
direction. We will need to keep track of the maximum value at any given track and we also have to do the pre-order
22:49:50
traversal for because we are following the principle of root then left and then right. And you can do this recursively
22:49:57
or iteratively it's up to you. Uh we will see that in the coding. If we see time complexity it's pretty
22:50:02
straightforward. It's going to be big of n because we are iterating over every single value. In terms of space
22:50:07
complexity, if you use the rec recursion method, it will take big of n. If you use iterative method, it would not take
22:50:14
big of n. And uh let's quickly see the coding solution for this one.
22:50:22
Okay. So, uh we are going to use a helper method called count good nodes to keep track of the good nodes we have
22:50:28
been able to identify and we are going to pass in the root value we found so far. Now this count good nodes is
22:50:35
actually going to return an integer value that defines that how many number of good nodes we have been able to identify for this particular uh root
22:50:42
node. Then we are in in the initial input we are just returning like the
22:50:48
minimum value possible because root in itself has to be greater than that. So root is going to be the first good node.
22:50:54
Okay. Now we are going to check okay that uh we are taking in as an input the tree node and the maximum node. So far
22:51:02
we are checking for an edge case that if the given node is equal to null we can simply return this zero. If that is not
22:51:08
the case we need to initialize our count to zero. Then we are going to check that if the given current node value is
22:51:15
greater than the maximum value we have been able to identify it. If that is the case then we are going to update the
22:51:22
counter to one. And we are also going to update the maximum so far to the current
22:51:27
node that we just found out. Once again we are going to repeat the same process
22:51:32
for the upcoming subsequent uh left child and for upcoming
22:51:38
subsequent right child and we are going to add the values of the left child and right child to our existing count value
22:51:45
as well. So whatever count they come back with we are going to add them to our existing count and in the end
22:51:51
whatever the final count we found we are going to return that and that would be returned as part of the answer for this
22:51:56
one. So that's it. Let's try to run the code.
22:52:02
Okay, seems like our solution is working as expected. Let's submit this code.
22:52:09
And our code runs 100% faster, which is pretty awesome because this has to be some of the fastest code because the
22:52:15
runtime is also not 0 millcond. So, we are doing something really awesome over here. Uh once again, solution is posted
22:52:22
on our GitHub repository. So, feel free to go ahead and check it out. Thank you.
22:52:35
Hello friends. So now once again let's do an awesome lead code problem that is going to solve all of your problems. So
22:52:41
without any delay let's get started. So the lead code problem we are going to
22:52:46
do today is called diameter of a binary tree. We can see that this one is an easy problem and also a very well-like
22:52:52
problem. The problem statement is quite straightforward. We are given the root of a binary tree and we need to return
22:52:57
the diameter of the tree. Now the question is diameter of a tree is the length of the longest path between any
22:53:05
two nodes inside this tree. And we are told that this path may or may not pass through the root but it's going to pass
22:53:12
through the root. Okay. Now the length of the path between any two nodes is represented by the number of edges
22:53:17
between them. So let's try to understand that how does a diameter of a tree is being calculated. Let's say that we are
22:53:24
given a tree like this. So in this case, what is the longest path we can make?
22:53:29
Well, let's just give them the number. So 1 2 3 4 and five. These are the numbers of this given nodes. So we can
22:53:36
see that the longest path over here is this one. So 3 2 1 and then five. This
22:53:41
is one path. Second longest path is once again 4 2 1 and five. So in either case,
22:53:47
the longest path we are able to make contains three edges. This is going to be the first edge. this or this either
22:53:53
one of them then this is the second edge and this is the third edge. So the answer is going to be three that this is
22:53:59
what we need to return. Now the problem statement is quite easy to understand but the thing is how do we actually
22:54:05
calculate the diagram um and if we start iterating over every single path and then try to find the answer then this
22:54:12
becomes lot of complication. So we need to avoid that. And if you look at it from the other way at any given moment
22:54:20
or at any given node the diameter of that node is nothing but the height on
22:54:25
the left hand side. So left hand height and the height on the right hand side. That's it. This is all a diameter is.
22:54:34
And we can see that in action over here that that the height on this left subree
22:54:41
is actually going to be two because it this is the first level and this is the second level and the height on the right
22:54:46
sub tree is going to be one. So if we do 2 + 1 the answer is going to be three. So this is what we need to calculate.
22:54:53
Now we need to understand that how we are actually going to be able to calculate that for any given binary tree
22:55:00
and for that we simply have to iterate over any given tree nothing more than that. Now iterating over the tree is
22:55:06
actually quite simple and we can use the common logic of recursion in this
22:55:12
problem. Now for recursion you know we need two items. First item is a base case. So base case in this case is going
22:55:18
to be that if the current node if that is equal to zero which means we have reached to the very end and now we
22:55:25
cannot go anywhere further. So then we start to do the backtracking. This is the first uh base case. Now the the what
22:55:34
is going to be the recursive equation or recursive scenario. Well, recursive scenario is quite simple that at any
22:55:40
given moment or at any given node, the height or the diameter of that node is
22:55:46
actually going to be the sum of the left diameter and the sum of the right diameter. And same way even at
22:55:52
subsequent left node, the diameter at that node is going to be sum of the left diameter and right diameter. And that's
22:55:59
how we should be able to calculate the answer we are looking for. So in this case, the height on the left hand side
22:56:04
is going to be two. The height on the right hand side is also going to be two. So the longest path we are going to be
22:56:10
able to make is going to be of size four. And we can also see some examples
22:56:16
of that. So one of the longest path starts from this node and then once again to this node and once again to
22:56:22
this node and then once again to this node and once again to this node. If we see the number of edges included this is
22:56:27
the first edge, this is the second edge, this is the third edge and this is the fourth edge. So this is exactly what we
22:56:33
are looking for in terms of finding the answer. So we all we also found out the recursive solution that the diameter at
22:56:40
any given node is going to be the sum of the left node or and plus sum of the
22:56:46
right node. Okay. And then we can have a recursive function to iteratively call
22:56:52
sorry recursively call our entire tree and then uh return back the answer. So
22:56:57
this is actually going to be the whole solution. We are simply iterating over the tree calculating the height and
22:57:03
whatever the sum of the height is we simply return that. If we see time complexity in this case the time complexity is going to be big of n where
22:57:10
n is the total number of nodes that are currently present inside the tree because we will have to iterate over every single node. And in terms of space
22:57:17
complexity well this is also going to be of n because we are using the recursion and in order to store the recursive
22:57:23
stack we might use of n space. So if you want you can also do this problem.
22:57:28
iteratively and in the iterative solution. We actually don't have to do or use the stack but the only reason I'm
22:57:36
using the recursive solution is because uh it's good to do it like recursively.
22:57:41
It's small amount of coding and also looks cool. Okay. So now let's quickly go to the coding.
22:57:51
So the coding solution is quite straightforward. uh we are going to initialize our variable maximum diameter
22:57:57
and we are going to have our method diameter of the tree from which we are going to call our get height method for
22:58:03
left and right sub tree for the given root element. Okay. Now this our get height method is our recursive method.
22:58:10
So let's quickly see what is happening the as a part of the base case we are having the scenario that if the given node is equal to null we need to return
22:58:17
zero. If that is not the case then we are going to find the height left height and the right height. For both we are
22:58:24
going to recursively call the get height method with the left child and with the right child. Now for every single
22:58:32
position we will have to check that have we reached a new maximum diameter. So for that we are going to do a simple
22:58:38
equation of the current maximum element or maximum diameter we have been able to find uh if that is greater or if we find
22:58:46
that the current left and right uh side uh sub trees height is greater than the
22:58:52
current maximum diameter we have been able to find then we need to update the max diameter. If that is not the case
22:58:57
then uh we can simply leave the max diameter as it is. Next we need to return the height uh that we have been
22:59:04
able to find. So in the end we are simply going to return 1 + the maximum
22:59:09
value of either left height or the right height. And why are we doing one plus? Because at any given root node we also
22:59:16
have to consider the node by itself before propagating the height to its
22:59:22
previous level. So that's why this one plus is there. Okay. With every new level basically we add one value to the
22:59:28
height. And uh this is the sol solution. Let's try to run the code.
22:59:36
Okay, seems like our solution is working as expected. Let's submit this code.
22:59:42
So, our code runs 100% faster than all the other solutions. And that's because uh the code actually operates on a very
22:59:50
simple principle and uh it runs in 0 milliseconds. So, that's why it's 100% faster. Uh it's nothing magic. Now, once
22:59:58
again, the coding solution is present inside our GitHub repository. Let me quickly show it to you that this is the
23:00:04
GitHub URL where we have actually stored hundreds of lead code questions and
23:00:10
their answers. Uh these are some of the most popular questions in the entire world. These questions has been asked at
23:00:16
tons of different companies multiple times. So for each of the problem you can go ahead and see. We have the Java
23:00:22
file for that. You can go and find the lead code link. you if you do don't find you can also find the subsequent video
23:00:29
solution and also a list of most most asked problems at the fang companies
23:00:34
which is this list which contains lot of important lead code problems they have
23:00:39
been differentiated based on the topics and for each of the topics I have provided that how many times they have
23:00:45
been asked at different top tier ID companies so there are 130 of most fabulous questions that I have been able
23:00:51
to find then also I have solved most of the need code 150s problems and they are
23:00:56
also provided over here. So this both of these resources are amazing.
23:01:11
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do validate binary search
23:01:17
state lead code problem. recommend if you see some of the companies where I want to get a job who already asked this question are companies like Amazon,
23:01:22
Microsoft, Bloomberg, Facebook, Uber, Google, Apple, Bans, Lyft, LinkedIn and Netflix. So that's why I'm paying my
23:01:29
utmost attention. I hope you also enjoy the video. This is a lead code medium problem and
23:01:34
one of the most liked tree problems on lead code. Uh basically we are given the root of a binary tree and we need to
23:01:40
determine that whether that given tree is a valid binary search tree or not. We are also given the definition that what
23:01:46
a valid binary search tree is. Basically uh for any given tree if this root value
23:01:51
or the node value uh so if this is the value of the node basically every single
23:01:57
value that is present on the left of the node should be less than whatever this node value is and every single value
23:02:02
that is on the right side of the node should be greater than whatever this node value is. So if that is the case and that is true for the entire given
23:02:08
tree, we can define it as a valid binary search tree. So let's take couple of examples that are shown over here. So in
23:02:14
the first example, well basically the node value we have is two. So the and in the left sub tree we only have one value
23:02:20
that is one which is less than this two. And on the right sub tree we only have one value again which is three which is
23:02:26
greater than uh this node value two. So in this case we can consider this to be a valid binary search tree and in this
23:02:32
case we will return true. But if we take a look at the second example. So in the second example we are given this root
23:02:37
value as five. So this value node value is five. That is okay. uh if you see on the left sub tree we only have one child
23:02:43
and that is the value is one. So this is again less than whatever the value we have for the node value. Now if we see
23:02:49
on the right sub tree the value of this is actually four. So four is again less than five. So because this four is less
23:02:56
than five and remember that we have the definition of valid binary search tree that everything on the right sub tree
23:03:02
should be greater than whatever the node's value is. So in this case this value is actually not greater than the
23:03:07
value of this root node. So in this case this is not in valid tree. So in this case we will return false and uh this is
23:03:13
what we have to define basically. Now based on the definition we can
23:03:20
define that what a valid binary search tree is that for any particular given node if it's left entire left sub tree
23:03:25
if that is less than the that node and if its entire right sub tree that is greater than that node we can define that to be a valid binary search tree.
23:03:32
Well, if that is the case, uh the first intuition that comes to our mind is that for any given node value, what we can do
23:03:38
is we can check its left child and right child. If the left child is less than it and right child is greater than it is.
23:03:44
If if that is the case, we will keep on repeating the same process for all the subsequent left child and right child
23:03:49
with its root node. And in in the end, if we reach to the end of this tree, we can return true immediately saying that
23:03:55
this is a valid binary search tree. Well, uh let's try to apply that same logic for this particular example.
23:04:00
Basically we are given this node five. So this three is actually less than five and 8 is actually greater than five. So in this case this portion is actually
23:04:06
valid. Now again for this three this one is less than it and four is greater than it. Again this portion is also valid and
23:04:12
uh same is true for this 8 6 and 9 as well. So in this case we can define this to be a valid binary search tree and we
23:04:19
can return true in this case saying that this is a valid binary search tree. But the thing is this solution is not the most optimal way to solve this problem.
23:04:25
And let me quickly show you why. Because based on the same logic for this five uh this three and 8 again okay this is less
23:04:32
than this is greater than. So so far this is valid. Again for this three this is 1 and four. So this is less than
23:04:37
greater than again this is valid. But now for this eight this is also 2 and 9. So this is less than greater than. Again
23:04:43
this is valid. So all three portions are valid. Uh by definition we would treat this to be a valid binary search tree
23:04:49
and that would actually be a false positive. Why? Because uh remember that by the definition for this uh node
23:04:55
everything that is on the right side of this tree should actually be greater than this node five but in this case
23:05:01
this two is actually less than this five and because of that particular case we will need to return false in this case
23:05:07
but I think it's based on our previous method we would have written true so let's see that what would be the actual optimal solution to solve this problem
23:05:15
so the idea for the optimal solution in this case is that we are actually going to do in order traversal on the given
23:05:21
binary tree to determine that whether it's a valid binary search tree or not. Well, if you want to learn more about
23:05:27
different types of tree traversals, you can check out the video over here. Now, let's get back to the question at the end. So, basically what the idea I'm
23:05:34
suggesting is that if we do in order traversal in any given tree, basically the idea for in order traversal is that
23:05:40
first of all, we visit the left sub tree, then we visit the node and then we visit the right sub tree. Also this in
23:05:45
order traversal is a depth first search kind of a traversal where we are actually going in the depth first and
23:05:50
then we are visiting the different nodes. So in this case the traversal that we are going to do is that first of all we are going to do the go for the
23:05:57
left sub tree. So for this node left node exist. Again for this node left node exist. So first of all we are going
23:06:03
to visit this left child. Then uh this child does not have any more children of its own. So now we are going to visit
23:06:09
its node. So we are going to visit this node three. And then again we are going to visit its right child which is four in this case. After doing that we are
23:06:16
going to visit the node and then we will keep on repeating the same process. So let's see that what is the path we are
23:06:22
going to take for this in order traversal. Well for this problem basically the path we are going to take is that first of all as mentioned for we
23:06:29
are going to visit this node number one. So first node is going to be one then going we are going to visit node number
23:06:34
three and then we are going to visit node number four in the fashion of left node node and then right sub sub node.
23:06:40
Then we again we are going to visit the node. So we are going to visit node number five. Now we are start we are
23:06:45
start going to keep on iterating on the right sub tree. So even on the right sub tree again we are going to follow this
23:06:51
method of left node and right. So for this left sub tree now this becomes the root node or the node and this also has
23:06:57
a left sub tree existing. So first of all we are going to visit this node number six. Then we are going to visit node number eight and in the end we are
23:07:04
going to visit this node number nine. So this is the in order traversal for this given binary uh tree. Now the thing is
23:07:11
if you see this uh traversal basically everything is going in uh increasing
23:07:17
order and this whole thing is actually sorted and this is the property of this in order traversal that we are going to
23:07:24
make use of and we are going to solve it optimally. The idea is uh for any given
23:07:29
tree that we are presented with we are going to do an inorder traversal. And during the in order traversal basically
23:07:36
the only thing we have to keep track of that any given node that we are iterating whether that node is actually
23:07:42
uh greater than its previous node or not. If it is not greater than greater than its previous node immediately we
23:07:48
can return false. So in this case because this was a valid binary search tree we were able to get an inorder
23:07:54
traversal that is completely in increasing order and all the previous nodes they are actually less in value
23:07:59
compared to its next subsequent node and this property is maintained throughout the entire journey. Now uh let's see one
23:08:06
example where this is not the case. So in this example we can clearly see that this node two is at the correct place
23:08:12
and this is not a valid binary search tree. So let's see the inorder traversal over here. So in this case the path is
23:08:19
going to be the next node we are going to visit is actually two. And if we compare this node two to its previous
23:08:25
value the previous value is actually five. Five is actually greater than this two which should not be the case. And
23:08:30
immediately at this point only we can conclude that this is an invalid binary search tree. We will return false
23:08:37
immediately in this case. And that is the answer we are going to use. Now actually there are two ways to do in
23:08:43
order traversal for any given binary search tree. There is an iterative way and there is a recursive way. If you
23:08:49
know me, I like the recursion better. So I'm going to show you the recursive way in the coding. But it can be also done
23:08:54
iteratively as well. And the tricky part in this problem is to identify that we need to solve this problem using in
23:09:00
order traversal. If you see time and space complexity in this case the time complexity is actually going to be big of n where n is the number of nodes that
23:09:07
are present. For the space complexity uh we are using recursion and we might have to uh store uh n characters in the worst
23:09:14
case scenario. First of all, we are actually going to
23:09:19
define a global variable called previous to store the value of the previous element. Now, let me create a new in
23:09:25
order method that would be our recursive method. So, now I have created a new in order method that returns a boolean
23:09:31
answer and we are taking just a root value as the input. Now, first of all, we are going to create the terminating
23:09:37
case that if the given root is equal to null, we are going to return true. If that is not the case, first of all, for
23:09:42
the in order traversal, we will have to call the leftmost function or leftmost value. So we are going to do that. So
23:09:49
first of all, we are going to see that if the answer for the root. If that is uh false, we will return false. If that
23:09:56
is not the case, we will move on towards our next condition. Okay. So if we did not return false from our left side
23:10:02
subree traversal, then we are going to check our condition. So the condition we are going to check is that whether the
23:10:08
current root value if that is less than or equal to the previous value if that is the case which means that we have
23:10:14
actually found an invalid binary search tree. So we can return false immediately. So if we don't return false
23:10:20
by this point which means the previous value was actually less than whatever the current root value we had which is a
23:10:25
good sign. So now what we are going to do is we are going to update the value of our previous uh variable. So that is
23:10:32
going to be the current root value and then after that we are going to call the right side sub tree as well. So we can
23:10:39
simply return the in order uh for the right sub tree. Now from our main method
23:10:44
all we will have to do is we'll set up we will have to set up the value of the previous character. Uh so initial value is going to be the null and then we are
23:10:51
going to call uh this uh in order method. Okay, seems like our solution is
23:10:56
working as expected. Let's submit this code and our submission runs pretty
23:11:02
efficiently compared to lot of other solutions and that is because the code runs in 0 millconds. Uh I would be
23:11:07
posting this in the comments so you can check it out from there. Thank
23:11:20
friends we are employed by fang company sol coding till we get there. Today we are going to the lowest common ancestor
23:11:25
of a binary search tree lead code problem. And if you see some of the companies where I want to get a job who already asked this question, there are
23:11:31
companies like LinkedIn, Facebook, Amazon, Apple, Google, Microsoft, Uber, Reddit and Twitter. So that's why I'm
23:11:37
paying my utmost attention. I hope you also enjoy the video. This is a lead code easy problem and
23:11:44
basically first of all we are given the definition that what a lowest common ancestor means. The lowest common
23:11:50
ancestor is defined between any two nodes P and Q such as that the lowest
23:11:55
node in given tree uh that has both P and Q as the descendants where we allow
23:12:00
a node to be a descendant of itself as well. We are given a binary search tree and we are also given two nodes in that
23:12:07
binary search tree. And now we need to find the lowest common ancestor between those given two nodes. Uh so let's try
23:12:13
to understand this with this example. Basically we are given a binary search tree over here and we are also given the
23:12:19
value of P and Q to be 2 and 8. So subsequently if we see over here two is located at this place and 8 is located
23:12:26
at this place. So the most common element or the immediate common common element that we can find is actually six
23:12:33
in this case. So that's why in this case we are going to return six as the answer because that is the lowest common ancestor between the node 2 and 8. Uh if
23:12:40
we take one more example in this case. So over here we are given this P is equal to 2 and Q is equal to 4. So P is
23:12:47
located at this 2 and Q is actually located at this four. Now if you see in this case actually this four is a
23:12:54
descendant of this uh two. So that's a given fact. But we are remember we are also told that we allow a node to be a
23:13:01
descendant of itself as well. So in this case uh since this two and four so four is already a descendant of this two and
23:13:08
two is already a descendant of its uh self. So in this case we will have to return this two as the answer and uh
23:13:14
that is what is given over here. We are given one more example where we are given only two nodes for this given
23:13:20
binary tree. So the binary tree looks like this two and one. And in this case we are given the value of this P to be
23:13:26
two and Q to be one. So again we can see that in this case this two is already a descendant of itself and this one is
23:13:32
actually a child of two. So because of that one is also a descendant of this two. So in this case we will again return this two to be answer. Now I hope
23:13:40
that this makes uh understanding the problem more easier and now let's see that what is the approach we are going
23:13:45
to solve this problem. Okay, first of all I'm actually going to
23:13:51
show you bunch of different binary search trees and for all of those binary search trees I have created some P and Q
23:13:56
values and we are going to see that what was the long lowest common ancestor and why that was the lowest common ancestor.
23:14:02
Right now we already know that important property of binary search tree and that is that for any given root value
23:14:08
everything on the left sub tree of that binary search tree is actually less than that and everything on the right side of that binary search tree is greater than
23:14:14
that. We already know this important property and we are going to take it to our advantage based on this given root
23:14:19
value or any root value and with subsequent P and Q values. So if we see over here in this case the given value
23:14:25
of P is actually six and if we start traversing through this binary search tree immediately we would find the six
23:14:31
to be present over here. So because we find the six to be present there can only be one possibility that this Q or
23:14:37
whatever the value of Q that would either be on the left side of the sub tree or right side of the sub tree but we already find the value to be six over
23:14:44
here. So immediately we can return six to be the lowest common ancestor because anyways this value of Q is somewhere
23:14:52
supposed to fall inside the remaining binary search tree and in this case it is on the right side of the sub tree. So
23:14:57
we will return six as the answer. This makes sense. Right? Now the next example uh again we are given the same thing. We
23:15:04
are given this value P to be 11 and Q to be 9. So we know that this P is over here and Q Q is over here. 11 is going
23:15:10
to be answer. But let's uh let's go ahead with our algorithm. So first of all we'll start iterating over this
23:15:16
root. So the root value is actually 8. Now for this root value we are going to compare it the with the values of P and
23:15:22
Q. Right? In this case the value of P and Q both are actually greater than this 8. So because both are the greater
23:15:29
than this eight. Uh we know based on the property of binary searchy that they are meant to fall somewhere on the right
23:15:35
side of this given binary search. So we will start iterating over the right side of the binary search tree to either find
23:15:41
the values of P or Q or if we can't find we will try to find the lowest common ancestor. So when we start iterating
23:15:47
over on the right side of the sub tree we will ignore this left side of the sub tree. We don't care. Now this value is 11. This value is 11 is actually matches
23:15:55
the value of this given P. So immediately whether when we whenever we find a match with either P or Q, we can
23:16:02
return that to be the lowest common ancestor immediately. In this case, this is going to be the answer because uh
23:16:08
this 9 is meant to be somewhere below this binary search tree and in this case it is immediately right here present. So
23:16:14
we will return this 11 to be the answer which is the lowest common ancestor. Let's take one more example which is
23:16:20
very similar. So in this case this value is P P is equal to 3 and Q is equal to 1. Now again based on our algorithm we
23:16:26
will start traversing over this binary search tree. Now the first value we traverse whenever we compare its value
23:16:31
with this P and Q immediately we find a match with this P to be over here. So
23:16:37
because we find a match over here do we really need to iterate over this given binary search tree? Well the answer is
23:16:43
no. Why? Because we know that this Q value is somewhere going to be down below and that is always going to be
23:16:49
this descendant of this P. So again we are going to return the values three as the lowest common ancestor. uh so far it
23:16:56
makes sense that whenever either we identify the value of P and Q we can return that to be the lowest common
23:17:02
ancestor immediately but what happens if the case is little bit different so in this case I'm give I have given the
23:17:08
value of P to be six and Q to be 9 right again let's start with our algorithm so we'll start iterating over this binary
23:17:14
search tree so first of all this value is actually five so because this value is five we'll try to see that okay we
23:17:19
will compare it with this value of P and Q right so actually this five is less than P and less than Q. Both P and Q are
23:17:27
greater than this root value. So immediately it is meant to fall somewhere on the right side of the sub
23:17:32
tree. So now we'll start iterating on the right side of the sub tree. We'll ignore these two because we don't need them. Now again this value is seven. So
23:17:40
let's compare this seven with this value of P and Q. Well, if we compare this seven, this seven is actually greater
23:17:47
than this P and this seven is actually less than this Q. Where right? So we can
23:17:52
conclude that this seven actually falls somewhere in the middle because uh on
23:17:58
for the seven on one side six is meant to be because six is less than seven and somewhere on the other side 9 is meant
23:18:04
to be because 9 is greater than the seven based on the property of a binary search tree. And if we utilize that to
23:18:10
our maximum advantage, we can immediately determine that the seven is the common point between this six and 9
23:18:17
where on one side six resides. So six resides on the left side over here and 9 resides on the right side of the sub
23:18:23
tree. So on the right side of the sub tree, this is where 9 resides. So we'll return seven to be the answer in this
23:18:29
case. And this is the approach we are going to follow. So every single time for any given tree, we will start
23:18:34
iterating over that tree and we are going to compare its value with P and Q. Based on that, we will decide that
23:18:40
whether we go on the left side of the sub tree or right side of the sub tree. The moment we find a match between P and
23:18:46
Q, whatever the value we found, if we find that we will return that to be the lowest common ancestor. If we don't find
23:18:51
a match and if we are in a situation where uh this value of P is on the left
23:18:56
side of this any root value and Q is on the right side of any root value, then immediately we can return that value to
23:19:03
be the answer. And this is the approach we are going to take to solve this problem. And uh this is the optimal way
23:19:09
to solve it. Now there are two ways to solve this problem. We can either solve it recursively or we can solve it
23:19:14
iteratively. Now I like recursion better but iterate iterative method will also work as expected in this case. Now for
23:19:21
the recursion if we see the time and space complexity the time complexity is actually going to be big of n because we
23:19:26
will have to iterate over all the values in the worst case scenario. And for the space complexity the space complexity is
23:19:32
actually going to be big of n as well because we will have to run maintain the runtime stack for this recursion method.
23:19:38
Well, uh, one good thing in iterative method is that for iterative method, the time complexity is still going to be big
23:19:44
of n. But for the space complexity, we can actually use a constant space complexity for the iterative approach.
23:19:50
But in the coding, because I'm trying to improve my recursion, I will be showing you the recursive method. But just
23:19:56
remember that iterative approach would be the better option in this this case.
23:20:03
So we are going to use the same method as our recursive method. And first of all in this method as an input we are
23:20:09
given this root value. We are given the value of P and Q. So first of all because we don't need to deal with this
23:20:14
tree node. We will actually have to deal with this integer value. So we are I'm going to initialize three variables uh
23:20:20
called the parent value P value and Q value. And I'm going to assign the
23:20:25
values based on this uh whatever the input we get. Now we will have to check that whether this parent value uh if
23:20:32
that is the common point between P and Q or either P and Q falls on one side or
23:20:38
other side of this binary tree. If that is the case we will call our recursive method again. So first of all we are
23:20:43
going to check that if this P value and Q value both are greater than uh this
23:20:49
parent value. If that is the case which means we will have to iterate on the right side of the sub tree. So we are going to call the iterative method on
23:20:55
the right side of the sub tree. If that is not the case, we are going going to check that whether this P value and Q
23:21:01
value both falls on the left side of this parent value. Uh so again we are going to do that. So if both P value and
23:21:08
Q value are less than the parent value which means we will have to search the left side of the sub tree. So we are going to do that. Okay. If that is not
23:21:15
the case which means that whatever this root info root value we are at that is either P or Q value. Uh which means we
23:21:22
can return root immediately. That's it. Uh that should be working. Let's try to
23:21:28
run this code. Okay, seems like our solution is working as expected. Let's submit this code. And
23:21:35
our code runs pretty efficiently compared to lot of other solution in terms of time complexity. I already mentioned you that the for the space
23:21:41
complexity this recursive solution is not the most optimal but I want to practice recursion. So that's why I did
23:21:46
that. You can find an iterative solution that works as well. And I would be sub uh I would be posting this in the
23:21:52
comments so you can check it out from there. Thank you.
23:22:04
Hello friends, we are standard note employed bifanging company. So let's not stop lead coding till we get there. Today we are going to do k smallest
23:22:10
element in binary search tree lead code problem. And if you see some of the companies where I want to get a job who already asked this question, there are
23:22:16
companies like Uber, Amazon, Microsoft, Facebook, LinkedIn, Apple, Google and Bloomberg. So that's why I'm paying my
23:22:23
utmost attention. I hope you also enjoy the video. So this is a lead code medium problem
23:22:29
and basically we are given the root of a binary search tree and we are also given an integer called k. Now we need to
23:22:36
return k smallest value from all the given values inside any given binary
23:22:41
tree. So let's try to understand this with couple of examples that are presented over here. So this is a binary search tree we are given. And if you
23:22:48
notice the important property of binary search tree where uh for whatever the root node everything on the left sub
23:22:54
tree is less than that root node and everything on the right sub tree is greater than that root node that is present for this BST. So that is the
23:23:01
definition of binary search tree. I'm just making it clear. And now for this example this is the binary search tree
23:23:06
we are given and we are also given the value of K to be one which means we need to return first smallest value. So in
23:23:12
this case the first smallest value or the smallest value is going to be this value one and this is what we need to
23:23:18
return as the output. Let's take one more example. So in this case again we are given a binary search tree and we
23:23:24
are also given the value of k is equal to three which means we need to return third smallest value. If we see in this
23:23:31
case this one is actually the first smallest value. Uh same way this two is the second smallest value and same way
23:23:37
this three is actually the third smallest value. So in this case we will have to return this three as the answer.
23:23:42
So I hope that you have understood the problem by now. Now let's see that what is going to be the optimal approach to solve this problem.
23:23:51
Okay suppose this is the binary search tree that we are given and we are trying to find the k smallest value at any
23:23:57
given position. So the idea I'm suggesting is that for this particular binary search tree if we make the sorted
23:24:03
array of all the values and we sort them in increasing order then whatever this array we have created that is already
23:24:10
sorted uh based on this it becomes pretty easy for us to find the k value. Uh how all we have to do is just look up
23:24:17
in this array and we we will be able to find the value. Let me quickly show you what I mean. So for this particular
23:24:22
binary search tree if we see the sorted path where the first value is one then
23:24:27
we have the value three then we have the value four and then we have 5 8 and 9
23:24:32
and this is the sorted path that we have we have been able to generate. Now once we have this value it becomes pretty
23:24:38
easy for us to find any k position. Uh how suppose we are given k is equal to
23:24:44
two we can immediately return second smallest value which is the second value in this case which is the value number
23:24:49
three. If we are given k is equal to 5, then we simply need to return this value number eight. Uh if we are given k is
23:24:56
equal to three, we can simply return this value number four. So now you you get the idea that once we have the
23:25:02
sorted path, it becomes pretty easy for us to find any k position. So all we will have to work on is that from this
23:25:09
given binary search tree, how can we actually create the sorted path? And if you know or if you have followed my
23:25:15
previous video, you know the answer. The answer is actually in order traversal. So let me quickly show you the optimal
23:25:20
solution using in order traversal for this problem.
23:25:26
Okay. So in order traversal actually a depth first search kind of a traversal which means that first of all on the
23:25:32
left side of the sub tree we go to the leftmost position then we visit its node or its root value and then we visit its
23:25:38
right sub tree and we keep on repeating the same process. So let's see that what is going to be the path in this case. So
23:25:44
path in this case is first of all we are going to visit the left most element which is one. So we'll visit node number one. Then we will visit node number
23:25:51
three. Then we will visit node number four based on following this left node and right formula. After that uh we will
23:25:58
visit the node again which is five. And then we will be on the right side of the sub tree. So again on the right side of
23:26:03
the sub tree we will have to follow the same path left node and right. But in this case since this right side of the
23:26:08
sub tree does not have any left children. So we won't be able to update or traverse any left value. But we would
23:26:14
be able to traverse the node value. So again we will travel the value eight and then in the end we would traverse the value number nine. So in this case this
23:26:21
is the path we are able to generate from this uh given input binary search tree using this in order traversal. And if
23:26:27
you see this path this is actually increasing order and this path is actually sorted which is very good for
23:26:33
us. So suppose we are given the k is equal to three. So if k k value is three we can simply return four immediately.
23:26:39
If we are given k is equal to 5 then again we can return this value number eight immediately as mentioned earlier and this is the approach we'll have to
23:26:46
take to solve this problem optimally. Uh now if you want to learn more about different kinds of tree traversal check
23:26:51
out my video over here. Now let's see the time and space complexity in this case. The time complexity is actually going to be big of n where n is the
23:26:58
number of nodes that are present inside any given tree. And if we see space complexity the space complexity is also
23:27:04
going to be big of n to accommodate our inorder traversal.
23:27:12
There are actually two ways to solve this problem. One is the recursive way and second one is the iterative way. Now
23:27:17
since you know me, I like the recursion better. And even in the coding, first of all, we are going to create our recursive method called in order and
23:27:23
that is going to return an array. So I have created the in order method that takes in a root value and also that
23:27:31
takes in an array list. Now first of all we are going to check the terminating case. So if the given route is equal to
23:27:36
null, we can simply return uh whatever the array value we have. Okay, if that is not the case, first of all, we are
23:27:42
going to call the uh in order function again and we are actually going to call
23:27:47
for the left subree. So we are going to call with the root. And we are also going to pass in the value of whatever
23:27:54
the array we already received. Uh once that is done, we are also going to add whatever the uh node value we have. So
23:28:01
we are going to add the value for that particular route and uh in the end we are also going to
23:28:08
call the in order method again for the right side of the sub tree because remember for the in order we are actually following the method of left
23:28:15
node and right. So with this time we are going to pass in the value of the right side right child and we are also going
23:28:22
to pass in the value of the uh whatever the array we have created. Now once this uh method runs simply we need to return
23:28:29
this array list that we have been creating. Okay. Now from the main method uh first of all we are going to create a
23:28:35
new array list called nums. In order to populate this we are actually going to call our in order method
23:28:43
and we are going to pass in the value of the root and we are also going to pass in the value of a new array list. Once
23:28:50
that is done, all we will have to do is basically from this array list, we simply have to return whatever the k
23:28:56
minus one's position element is because remember this k is actually one index.
23:29:01
Meanwhile, the array list we have been creating that is zero index. So that is one tricky thing that we will have to
23:29:07
take care of. Uh let's try to run this code. Okay, seems like our solution is working
23:29:12
as expected. Let's submit this code. And our code runs pretty fast compared to a lot of other solutions. It is also
23:29:19
very efficient in terms of space complexity as well. And I will be posting this in the comments so you can check it out the solution from there.
23:29:35
So the lead code problem we are going to solve today is called find leaves in a binary tree. And this one is actually a
23:29:41
lead code premium problem. And that's why you see that the UI looks slightly different. Now let's try to understand
23:29:46
the problem statement. We are given a binary tree and we need to collect trees
23:29:52
nodes as if we are doing the following where we are collecting and removing all
23:29:57
the leaves inside the given tree and we are going to repeat this until the entire tree is empty. Now we all know
23:30:04
that what does a leaf node in a tree looks like? Basically the node that does not have any children is referred as a
23:30:11
leaf node. So what we need to do is that for any given binary tree we are given
23:30:16
the root of it. We need to iterate over the entire tree. Find that what are all
23:30:21
the leaves that it currently has. Collect all every single leaves in one order and then repeat the same process
23:30:29
with all the remaining nodes. So in this case we can see that at the beginning these three are the leaf nodes. So we
23:30:35
are going to mark these as the leaf nodes and we are going to collect them in the answer. So we will collect four,
23:30:41
five and six as part of the first set of leaf nodes. Then we would get rid of these nodes. Then once again we would be
23:30:48
left with another set of leaf node that is that are going to be nodes two and nodes three. So that they would come in
23:30:55
in the second portion of like collecting leaf nodes. Once we get rid of them uh in the end we will only be left with the
23:31:02
root node and that is going to be value number one and that is all what we need to return. So this is the whole problem
23:31:09
solution. Now you can imagine that solving this problem seems quite trivial.
23:31:17
All we are doing is that at every given instance we are basically iterating over
23:31:22
the given tree and we are trying to find that what are the leaf nodes. So we know that what is the condition of any
23:31:28
particular node to define that it is a leaf node or not. Well, we can check that if for any particular node, if the
23:31:36
left child is equal to null and if it's the right child is also equal to null and the node is currently not equal to
23:31:43
null, which means the node exist. So in that case we can define any particular node to be a leaf node. So we know that
23:31:50
how to identify a leaf node. Second thing is we need to store every single
23:31:55
leaf nodes that we collect. Which means we will have to create an array list where we are going to store bunch of
23:32:02
different array list for every single piece of lead code uh leaf nodes that we found. Okay, that is second thing. Third
23:32:09
thing is how are we going to iterate over the given input and for that there are actually couple of ways but in this
23:32:15
case recursion would be a very good approach to reach out and solve this problem because we know that in the
23:32:22
recursion we basically need to repeat the same process and same goes in this problem as well that first of all for
23:32:29
this entire given root node we will need to find the leaf nodes. Same thing happens when we do go to the left child
23:32:35
and right child. Once again at the left child and right child level we need to find the leaf nodes. So currently this
23:32:41
one is a leaf node in itself. So we will mark it to the answer at the right child level. Sorry left child level. Once
23:32:48
again we will still repeatedly try to find the same things. Once we find the all these three leaf nodes we will mark
23:32:54
them in into the answer. Remove them from the existing tree. So declare that the current node is equal to null and
23:33:00
then once again repeat the same process from the root. So let's try to understand the the solution I'm
23:33:06
suggesting in action. Let's just give some arbitrary values to these particular nodes. Okay. So in the
23:33:12
recursion we know we need two items. We need a base case. So base case is quite straightforward. The definition on how
23:33:19
to define any particular leaf node that we just saw that if the given left child is equal to null and the given right
23:33:26
child is equal to null for any particular node, we can define that node to be null. That is the first base case.
23:33:32
Second base case is that if the node in itself is null then we are simply going to return null. In that case we don't
23:33:37
need to do anything but we if we do identify at any particular moment that if left child and right child both are
23:33:44
null then we need to add that particular node to the answer array list that we have created for the current set of leaf
23:33:51
nodes. Okay. And what would be our recursive case? So recurs uh recursive
23:33:56
function is going to be quite simple that if the node has some left child and
23:34:01
it if the node has some right child then recall the same recursive method once again until we reach this base case and
23:34:08
we would have added all every single value inside the answer. So let's try to see the solution in action. First we are
23:34:13
at this root node. Currently root node does have left child and does have right child. So once again we are going to do
23:34:19
the recursive function. So if we apply the recursive function we are going to reach over here once again for left
23:34:25
child we once again find it does have left child and right child for right child it does not have any any other
23:34:31
values. So we and also for the these subsequent values of left child and right child we see that they don't have
23:34:37
any children of their own which means all of these are identified as the leaf node. So we are going to mark values
23:34:44
four five and three in the answer as first set of leaf nodes. After declaring them, we are going to eliminate them
23:34:50
from the given input. And now once again, we are going to repeat the same process starting from the root node. So
23:34:56
currently for this root node, it still has a left child. Once again, for this leaf left child, it does not have any
23:35:01
child of its own. So this is going to be another set of leaf node. And in the end, we will also get rid of this one.
23:35:08
And finally, we are at the root node. So once again, recursively, we find out that root node does not have any
23:35:14
children. It meets the base case. So we are going to add it to the answer as well and this is the answer we are going
23:35:19
to return in the end. So logically this is a very simple tree traversal program
23:35:24
problem but with every single traversal we just want to repeat the same process by eliminating few nodes and keep on
23:35:31
doing it again and again till the entire tree is empty. So this is the whole solution. If we see time and space
23:35:37
complexity in this case, the time complexity is simply going to be big of n where n is the total number of nodes
23:35:43
present because we will have to do it for each one of them. Even for the space complexity in order to maintain the
23:35:48
recursive stack it is going to be bigo of n. And also we need to create an extra array list to store the answer and
23:35:55
that is going to be completely dependent on the total number of nodes that are currently present. So overall this is a
23:36:00
very good question and a good amount of time in space complexity. If you do encounter this in any of your interview,
23:36:06
don't get afraid or don't worry because this is like a simple approach on how you can traverse the tree and find the
23:36:13
best solution that is asked. Uh now let's quickly see the coding solution for this one.
23:36:20
So here is the coding solution for this one. Once again we are running it in an online compiler and not in the lead code
23:36:26
because this is a premium question. So here is the definition of our tree node. Uh it's a just a standard tree node. Now
23:36:32
let's quickly look take a look at our class solution. So first of all we are going to create a method that calls
23:36:39
collect leaves method that provides in the root of the tree and in the answer we are going to return an array list
23:36:45
that contains list of values that where we have all the leaves connected based
23:36:50
on the edge cases for every single iteration. Now first of all we are going to define the result where we are going
23:36:56
to return as part of the array list and we are simply going to run a while loop that while the given root is not equal
23:37:03
to null we are going to repeatedly do this where first we are going to create
23:37:08
a simple array list to collect leaves in that particular iteration of that tree.
23:37:14
So this is going to provide us the leaves level by level. Then we are going to provide the results by calling the
23:37:23
remove roots method where in the remove roots uh sorry remove leaves method we are taking in a tree node and we are
23:37:30
also taking in the current set of leaves as an input and we this is going to be our recursive helper method where first
23:37:35
we are checking that if the given node is equal to null we can simply return null. If that is not the case we check
23:37:42
that if the given node is a leaf node. If that is the case, we are going to add it to our leaves uh uh array list for
23:37:50
now and then we are going to remove it and if that is not the case both for left and right child we are going to
23:37:56
call the remove leaves method once again and in the end we are simply going to return the node. So this is our helper
23:38:03
method where we are recursively iterating over the any instance of the tree based on the given uh node that we
23:38:10
are provided. And once we return that back to root we are simply going to add
23:38:15
those results that we found in inside the leaves as part for the uh in the result array list that we have created.
23:38:22
In the end we can simply return the results. Now I have also created a main method and just created like some dummy
23:38:29
cases to see that where what are what is the answer we find and we can see that the root node is one and then it has a
23:38:36
left child two and the right child is three and once again for left child it has four as its left child and five as
23:38:42
its right child and so on and so forth. So if we try to run this code we should be receiving uh the answer as expected
23:38:50
and we can see that in the first iteration we remove 4 5 6 as leaf nodes then we remove 2 three as second set of
23:38:57
leaf node and lastly the root node one. So this is the answer once again the
23:39:02
solution is present in our GitHub repository. So feel free to go ahead and check it out from there. Thank you.
23:39:18
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do construct a binary tree
23:39:25
from pre-order and in order traversal lead code problem and if we see some of the companies where I want to get a job
23:39:30
who have already asked this question there are companies like Microsoft, Amazon, Bloomberg, Apple, Uber, Bite
23:39:35
Dance, Google, Facebook and LinkedIn. So that's why I am paying my utmost attention. I hope you also enjoy the
23:39:41
video. Now, this is a very hated lead code problem and let me show you why. This is from the solution tab of the
23:39:47
lead code problem where people have expressed their views very abruptly. Some people are saying why God why. Some
23:39:53
people are saying that it's time to leave for Himalayas. Some people are saying that if you get this question they do not want to hire you and things
23:39:58
like that. There are many other comments. The thing is we do not want to focus on the negativity. Let's try to
23:40:04
see that what is the approach to solve this problem and then we are going to see that how can we be able to solve this problem. if we encounter this in
23:40:10
any interview because our aim is to get into fang not just dream about it.
23:40:17
Now this is a lead code medium problem but in my opinion this should have been a lead code hard problem. Now let's try
23:40:22
to understand the problem. Basically we are given two integer arrays called pre-order and in order and basically
23:40:28
they are the pre-order traversal of a binary tree and in order traversal of the binary tree. Now based on these two
23:40:34
arrays that we are given we need to construct and return the original binary tree. So let's try to understand this
23:40:40
with an example. So over here we are given as an input we are given two different arrays preorder array and in
23:40:46
order array. Now somehow if we iterate over this pre-order and in order array there is only one combination of binary
23:40:52
tree we can make and which is this one. So that is the example that is given over here. Now let's see that what is
23:40:57
going to be the different approach to solve this problem. But before we do that, the important thing in this problem is is to understand that what is
23:41:04
a pre-order traversal, what is the in order traversal and how can we use their properties to our advantage. So first of
23:41:10
all, I'm going to show you pre-order and in order traversal how it works. So first of all, we are going to learn
23:41:17
about pre-order traversal and basically pre-order is a DFS kind of traversal which is depth for search. If you want
23:41:23
to know more about different kinds of traversal, you can check out my video over here. Now let's focus on the pre-order traversal for now. So
23:41:29
basically in pre-order traversal first of all we visit the root node then we visit its left sub tree and then we
23:41:35
visit its right sub tree and we keep on doing that until the nodes exist. So let's see that for this given example
23:41:40
what is going to be the path that we are going to follow. So first of all we are going to visit the root node. So in this
23:41:45
case the first node we are visiting is going to be node number five. Then we are going to visit its left child. So
23:41:50
left child in this case is three. So again we are going to visit node number three. And then again we are going to visit its left child because remember
23:41:57
it's root left sub tree and right sub tree. So left sub tree still exist over here. So we are going to visit node number one. Now left sub tree does not
23:42:03
nothing more exist in the left sub tree. So now we will start visiting the right sub tree. So we now we will visit the node number seven. Now after visiting
23:42:10
the node number seven now there is nothing exist over here. So again we are going to go back to the root because we still have to visit its right sub tree.
23:42:17
So we when we start visiting the right sub tree again we are going to follow the formula for root left and right. So
23:42:23
root node in this case is going to be eight. So now we are going to visit node number eight. After that we are going to visit node number six and then we are
23:42:30
going to visit node number nine which is the right sub tree. And this is going to be the traversal path that we are going
23:42:35
to take. Now let's see that what would be the in order traversal in the same manner.
23:42:41
So again as mentioned the in order is also a DFS kind of traversal but in this case the methodology we follow is that
23:42:47
first first of all we visit the left node then we visit the root node and then we visit the right node. So for
23:42:53
this given example what we are going to do is first of all we are going to go to the left node all the way possible. So
23:42:58
left node in this case is one. So first node we are going to visit is going to be node number one. Now for uh now we
23:43:04
can't go left anywhere anywhere. So now we are going to visit its root node. So root node is in this case is going to be
23:43:10
three and then we are going to visit its right node. So right node in this case is going to be seven. After doing that
23:43:15
after visiting all three nodes now we don't have any more nodes to travel on the left sub tree. So now we are going
23:43:20
to visit the root node as mentioned over here because we have already taken care of this left part. So now we are going to visit node number five. Now again we
23:43:27
still have values that we need to visit on the right sub tree. So again we are going to take on the same initiative. So
23:43:33
now the first thing we are going to visit is going to be the leftmost element for this right sub tree. So leftmost element in this case is six. So
23:43:39
we are going to visit the node number six over here. After that we are going to visit the root node which is eight.
23:43:45
And then in the end we are going to visit the node 9 over here which is this one. So this is how in order traversal
23:43:52
works. So after understanding both the values and both the different traversal mechanism let's see that what would be
23:43:58
the optimal solution and how we are going to approach that.
23:44:04
Okay suppose this is the binary tree that we are given that we need to iterate over and we are given the
23:44:10
pre-order and in order traversal for both of them. So in that this case the pre-order traversal for this tree is
23:44:16
going to be and the inorder traversal in this case is going to be. Now once we
23:44:22
have both the values let's see that what is the approach we are going to take. So if you closely observe both of these
23:44:29
values for pre-order and in order traversal they both have something to offer. The thing they have to offer is
23:44:35
that this pre-order allows us to determine that what the root of any section of the tree is and this in order
23:44:41
allows us to determine that what is the left subree and what is the right sub tree of any given tree. How? Let me
23:44:48
quickly show it to you. So if we see this pre-order traversal the first value in this case is actually the root of the
23:44:54
binary tree which is five over here which you can clearly see that the five is the root of the binary tree. So well
23:45:00
that is interesting information but thing is this alone is not helpful. If we see with this in order traversal for
23:45:06
this five if we see the left side of this five there is only one entry over here which is three. And if we see in
23:45:13
this tree actually this three is the left sub tree of this entire tree that where the root is five. Now if we see on
23:45:20
the right side the values are 6 8 and 9 which is these three items and this is actually the right sub tree of this
23:45:27
original given tree where the root value is five. So now we actually have something meaningful that we can use if
23:45:33
we keep on repeating the same process. Now for this pre-order traversal again we see okay so the next value is three.
23:45:40
So three is already the left sub tree. Now if we again break it from this in order traversal for this in order
23:45:47
traversal we only have three value over here. We have nothing on the side. We have nothing on the right side because
23:45:52
the right side value is actually five which we have already identified that that is the root of this original value
23:45:57
three. Which means we can determine over here that for this three it does not have any values on the left subchild and
23:46:03
right subchild because the very next value of this three is actually five which was already the root of this value
23:46:09
uh three. So now again we have some meaningful information. So, so far let's backtrack the information we have found
23:46:15
so far that let me create an answer value over here where we have already found that okay the first value is five.
23:46:21
Uh the leftmost value or the first left value or left subchild of this value
23:46:26
number five is actually three and for this three it does not have any more children. So now we can add the values
23:46:32
null null over here. Okay. Now we are done iterating up until this point but we still have some more
23:46:38
nodes that we need to iterate over. So based on this pre-order traversal now the next node we have is 8. So now we
23:46:44
know that the current route we are iterating over is actually 8. Okay. So we have this value 8. Now from this uh
23:46:51
in order traversal we actually have these three values where this eight is actually in the middle because remember
23:46:56
this in order traversal allows us to determine that what is the left sub tree and right sub tree of any given route.
23:47:02
So in this case if the root is eight then the left sub tree is going to be the value six and the right sub tree is
23:47:08
going to be the value number nine. So we are going to use it to our advantage. Now uh for this value number six again
23:47:14
we are going to try to see that what is on the left of six and right of uh six.
23:47:19
But in this case since we don't have any more information for this value number six the left value is five which was the
23:47:25
original root which we have already iterated over. And this next value is 8 which was the original the root of
23:47:32
immediate root of this value number six which we have already iterated over. So now we can determine that for this six
23:47:37
we don't have any other value. So which means that we have two null values. So again now let's and same thing we can
23:47:44
determine for this nine as well that for this nine the leftmost value is actually eight and the in the right there is
23:47:49
nothing over here which means this n also does not have any more children. So now let's again backtrack based on the
23:47:55
information we have found so far. So now on the right side the value we got was 8. That was the root we iterated over
23:48:01
and we found that information based on the pre-order traversal. After finding this eight, now we started iterating
23:48:07
over the left and right children of this eight. So left children was six. So we iterated the value six. Now the six did
23:48:13
not had any more children. So we had the values null null over here. And now then we had the value number 9. And 9 also
23:48:20
did not have any more children. So now again we had the two more null values over here. And this is the actual binary
23:48:26
tree that we were able to create based on this original given pre-order traversal and in order traversal. And
23:48:33
that is the solution that your interviewer is expecting and that is what is needed for this problem as well.
23:48:39
Now there are actually two ways to do this problem. The there is an iterative way and there is a recursive way. If you
23:48:45
know me I love the recursive solution. So I'm going to opt for the recursive solution. Basically what we are going to
23:48:51
do is initially we are going to find the root value and then we are going to find the left sub tree and right sub tree.
23:48:57
Now again we are going to pick one value. So we are going to pick the left sub tree. So now even for the left sub
23:49:02
tree we will have a root value and it's left child and right child and again we are going to keep on repeating the same process and we will be continuing to
23:49:08
building our answer and same thing we are going to repeat for our right sub tree as well. So basically we are taking a bigger problem and then dividing it
23:49:15
into a bunch of different smaller problems. I know this looks really messy but you get the idea of what I'm trying
23:49:21
to convey over here and let's see the time and space complexity in this problem. So time complexity is actually
23:49:26
going to be big of n where n is the number of nodes that are present inside any given tree because we will have to
23:49:31
iterate over both in order and pre-order traversal and originally it's going to be 2 n traversal. The thing is
23:49:37
generically we can write it to big of n. If we see space complexity well space complexity is also going to be big of n
23:49:44
because recursively we might have to iterate over all the nodes and it worst case scenario it could take big of n
23:49:49
space. This is a wonderful time in space complexity given that how complex this problem was and based on the pre-order
23:49:55
and in order traversal we were actually able to build the solution for the binary tree. Now let's see the coding.
23:50:03
So before we start coding we will actually have to define that how we are going to use this pre-order and in order array. Well we are going to use this
23:50:09
pre-order array to determine that what is the root value for any subsequent positions. And once we have the root
23:50:15
value, we are actually going to use this in order array to determine that what is the left sub tree and right sub tree for
23:50:20
any given route. And once we have both the information, we are actually able to build our tree. Now the thing is if you
23:50:26
clearly understand that for this in order array, we will have to look up at information much in much broader fashion
23:50:33
than compared to this pre-order array. Uh so what we can do is in order to iterate over this in order array rather
23:50:40
than iterating it just by considering this to be an array we are actually going to create a hashmap where we are
23:50:46
going which is going to allow us to iterate over this in order array pretty fast and uh so let me define two global
23:50:54
variables over here. First of all, once you have these two information, now from our main method, first of all, we
23:51:00
will have to iterate over this in order array and then we will have to populate this in order index map that that we
23:51:06
just created. So, let me quickly run a for loop. Uh now we have our hashmap ready to go. Now we will have to create
23:51:13
a separate method where we are going to call the recursion. So first of all, let me create a new public method. So now I
23:51:20
have created a new method called array to tree uh that returns a tree node and as an input I'm taking the pre-order
23:51:26
array the left portion and right portion uh and now we are going to create this
23:51:31
uh recursive method. Now before I do that I will also have to initialize the values for this pre-order index and also
23:51:37
for this in order index map. So that I'm going to do it. Okay. Now back to our uh
23:51:42
recursive method. So for recursion first of all we will have to create a ter terminating case and the terminating
23:51:48
case in this case is going to be that if the value of left is greater than the value of right. If that is the case we
23:51:54
break out immediately and we will return null. If that is not the case first of all we'll have to define our root value
23:52:00
and root value we are going to define from our pre-order array. So our root
23:52:05
value is actually going to be the whatever this pre-order index value that we have. uh and then we are also going
23:52:13
to uh increment the value of this pre-order index as well. So uh this is the root value and after that we are
23:52:21
going to increment the value of pre-order index. Now since we have a root value we are actually going to
23:52:26
create a new tree node called root and for this root node we are going to
23:52:32
assign the value that we received over here. Originally the value of this pre-order index is zero which means that
23:52:38
the first value we are getting from this pre-order is the main root of the tree. Once we get that value we will have to
23:52:45
create the left sub tree and right sub tree. So we will have to call this array to tree method again and we are going to
23:52:52
populate the value for left and right child. So for the left child we are again going to call this array to tree
23:52:57
method uh inside the input. First of all, we'll we are going to provide this pre-order array as we found as it is.
23:53:04
Now, for the left sub tree, we are going to keep the value same for the left value. But for the right portion, the
23:53:11
value is actually going to be different. And that is going to be different based on whatever this root value we had. So
23:53:17
in this case, for the first value for this pre-order array, the root value is actually three. So now for the left part
23:53:24
we already have the value but for the right part we are going to have to provide all the values that are present
23:53:30
after this root node. So we are going to do that. So for that uh now our uh in
23:53:36
order index map is very helpful. Now we have both the information ready to us.
23:53:41
Now we are uh now we are going to call the right sub tree in the same manner but in this portion we are going to
23:53:47
treat whatever the right variable we had already. uh but now we are going to change the left variable. So left for
23:53:54
the left variable we are actually going to use whatever the value we had for the root value and we are going to do it +
23:54:00
one and uh as the right limit we are going to keep whatever the right limit
23:54:07
we originally had and after this recursion ends and after this function ends we simply need to return the root
23:54:14
variable. Okay. So now our recursive method is ready to go. Now all we will
23:54:19
have to do is from our main method we will have to call this uh recursive method that we just created. That should
23:54:26
be it. So we are we are calling this pre-order method but we are providing the pre-order array and as the left uh
23:54:34
position we are providing the value zero. As the rightmost position we are providing the value of whatever the pre-order length is minus one. And uh
23:54:41
that should do the trick. Now let's try to run this code.
23:54:48
It seems like our solution is working as expected. Let's submit this code. And our code is pretty efficient
23:54:55
compared to a lot of other solutions. I will be posting this in the comments so you can check it out from there.
23:55:09
So today we are going to do serialize and deserialize binary lead code problem. And if you see some of the companies where I want to get a job who
23:55:15
already asked this question, there are companies like Amazon, Microsoft, LinkedIn, Uber, Google, Facebook, Door
23:55:21
Dash, Tik Tok, Apple, Snapchat, Splunk, and Goldman Sex. So that's why I am
23:55:26
paying my utmost attention. I hope you also enjoy the video. Hello friends, the reason I have not
23:55:31
been uploading in recent days is because I just had twin baby girls. And uh so yeah, that's the update. And now let's
23:55:38
move on to the video. So lead code thinks that this is actually a hard problem but in my
23:55:43
opinion this is not a hard problem. It's actually very creative problem. Uh basically we need to serialize and des
23:55:49
serialize the given binary tree. Now first we'll have to understand that what the serialize and des serialize means.
23:55:55
Well, uh, serialization is the process of converting the given data structure which is tree in this case and we need
23:56:01
to convert that into a sequence of bits so that it can be stored in some memory
23:56:07
or file buffer and then we can transmit it across any network. Now in this problem basically we need to design an
23:56:13
algorithm where we are actually serializing and deserializing a binary tree. So serializing means that first of
23:56:20
all we are finding a way to convert the given binary tree in some sort of uh bits and in this case we are told that
23:56:27
we need to convert it in strings. So we are familiar with that and then des serialize means that we need we are
23:56:32
given this string and we need to write an algorithm to convert this string back to a binary tree. So we'll have to do
23:56:39
both the things and if you see this problem this is actually very similar problem that we did earlier with
23:56:44
strings. Uh this is the solution of that problem. So go and check it out first. Now we are also given a clarification
23:56:50
that we can be as creative as we can with the serialization and uh des serialization process. So we can have
23:56:57
different way of serializing the tree and different way of deserializing the tree as long as we maintain the tree
23:57:02
data structure. Uh so let's see that what is the approach I am suggesting and you can also come up with your own own
23:57:09
creative approach. Well, basically in this problem we are
23:57:14
only given the root of a tree and then somehow we will have to go over the entire tree and then uh traverse it
23:57:21
convert this given root and all of the entire tree into a string and after we have converted it to string we will have
23:57:27
to find a way that suppose if we are given this string as the input how can we convert from the string this binary
23:57:33
tree as well. So we are doing both the process. So the important thing in this case is that we will have to traverse
23:57:39
over the given binary tree. So there are mainly two strategies to traverse over the given binary tree DFS and BFS and I
23:57:45
have explained this very carefully in the previous video. You can check it out over here. So basically in this video
23:57:50
what I'm suggesting is that we actually go with pre-order approach with using DFS to serialize and deserialize this
23:57:58
given binary tree and I would be showing you that what is the process we are following.
23:58:03
So first of all we are going to serialize this given tree which means we are going to take this binary tree and
23:58:09
we are going to convert it to a string. Now as mentioned earlier we are going to use the pre-order traversal for that. So
23:58:15
if you are not familiar with the pre-order traversal basically we visit the root node first then we visit the left child of this root node and then we
23:58:21
visit the right child of this root node and that is how we are going to end up creating the string from this given
23:58:27
binary tree. So let's see that in action. So first of all let's create a variable called s or string where we are
23:58:33
going to store the string value. So first of all we are going to visit the root node. The root node in this case is one. So we are going to add an entry
23:58:40
called one over here. Now we need to visit the left child of this root and then we need to visit the right child of
23:58:45
this root. Now remember this is actually a DFS policy. So in the DFS we go in the depth first. So first of all we are
23:58:51
going to visit the left child. So left child in this case is two. So we are going to add an entry that two is the left child over here. And then again for
23:58:59
this two because we still have left child left. So we are going to visit that. So for this two the left child in
23:59:05
this case is actually four. Now for this four we don't have any more left child
23:59:10
and we don't have any more right child. Which means that first we try to visit the left child. For this four there is
23:59:16
no left child. So we enter a value called null over here. And then for this four again there is no right child. So
23:59:22
again we add value null over here. saying that for this four the two left child and right child is actually a null
23:59:28
value. Now after that we still have nodes left that we haven't visited for. So now for this node two we have this
23:59:34
node five and it's right. So again we are going to enter the value five over here. After entering the value five we
23:59:41
are again going to check the left child and right child for this five. So left child in this case is null and again
23:59:47
right child is also null. So we will add two more entries null null again. And now we go back. So now we have visited
23:59:54
all of these nodes but the thing is we haven't visited the right portion of this original root node. So again we'll
24:00:00
have to iterate over the right sub tree. So right sub tree in this case is going to be three. So we add three over here.
24:00:05
Now for this three again we don't have any more children node. So again we add two null values.
24:00:11
So this is the answer in this case that we have to return for this given tree
24:00:17
that this is the string value that tree represents this given binary tree. Now let's see that what would be the des
24:00:23
serialization process. So now we are going to work upon the des
24:00:28
serialization. So basically we are going to convert string into binary tree. So the idea is this is the string we
24:00:34
generated from the serialization process. Now again we are because we are using pre-order traversal. We are
24:00:41
actually going to apply the same logic. So we are going to treat the first node to be the root node. And then the next
24:00:47
node would be the left subchild of this root node. And the next node is going to be the right subchild of this root node.
24:00:52
And we are going to keep on iterating this process in in reverse order. So the idea is that first of all, okay, we
24:00:58
identify this node. So this node is actually our root node. Okay. So root node is actually one in this case. Now
24:01:03
again this two is actually a left child of this root node. So because this left child exists, the ne the next node is
24:01:11
again going to be the left child of this node two. So again we are going to create a node four that is left child of
24:01:17
this node. Now for this four the next two nodes are actually null null. So because we encountered two null values
24:01:22
which means this four does not have any more children. So we can just ignore that. Okay. Now we still have a node
24:01:28
five which means that this five is actually the right child of this two because we have already visited the left
24:01:33
subree of this two. So now because we are done with the left sub tree now we are visiting the right sub tree. So we
24:01:38
are going to create one more entry five over here as the right sub tree. Again we have two more null values which means
24:01:44
that this right sub tree is done. Now we don't have any more values. Okay. Now we still have values which means that this
24:01:51
actually refers to a root node where we haven't visited the left and right sub tree because remember that this is the
24:01:58
left sub tree we have visited for this two and this is the right sub tree we have visited for this two but we haven't
24:02:03
visited the right sub tree for this original one. So now we are going to do that. So now we are going to add one
24:02:08
more entry three over here which is the right sub tree of this original given one and this three actually has null
24:02:14
null values which means three does not have any more children. So we won't be adding any more entries over here and we can just ignore that. Now we have
24:02:21
reached the end of the string. So because we have reached the end of the string we have created the binary tree that we are supposed to create and we
24:02:27
have completed the des serialization process and we have converted the string into the binary tree. So this is the
24:02:33
approach we are going to take. If we see the time and space complexity in this for the serialization process, the time
24:02:38
complexity is actually going to be big of n because we have to iterate over n
24:02:43
characters that are present and the space complexity is also going to be big of n because we will have to create a
24:02:49
string where we are storing all the n values. Now for the d serialization process again the time and space
24:02:54
complexity remains the same. Now we will have to create two methods uh for serialize and des serialization. So
24:03:00
first of all we are going to work upon serialized process. So I'm actually going to create a new public method uh
24:03:06
that returns a string uh where recursively we can apply the pre-order traversal and as an input it is going to
24:03:14
take the root value and we we are also going to pass the string value. Now
24:03:19
inside this recursive function first of all we are going to find the terminating case. So if the given root is equal to
24:03:24
null and simply add the value to the string as null. If that is not the case
24:03:29
which means that root still has some value and it could have left sub tree and right sub tree. So now we are going to call the recursive function. So first
24:03:36
of all we are going to add the value to our string. Now we are going to call the left sub
24:03:41
tree and right sub tree. So we are again going to call this recursive serialize method.
24:03:47
Again we are going to repeat the same process for the right sub tree. Once this ends we are simply going to return
24:03:52
the string. Now from our main serialized method, all we have to do is just call this uh recursive serialized method and
24:03:58
return whatever the answer we get. We are going to pass in root as an entry and we are going to pass in an empty
24:04:04
string. So now we are done with our serialized method. Now let's work upon
24:04:09
des serializing method. Now again for the des serializing process uh first of all we will have to create a recursive
24:04:16
method to iterate over this given string data and then we are going to convert
24:04:21
all the string values into binary tree. So we are passing a list of strings in this case for this recursive d
24:04:28
serialized method and now first of all we are going to work upon the terminating case. If the given node is
24:04:34
null we can simply remove the value and then we can return null. Okay, if that
24:04:40
is not the case, first of all, we are going to note the whatever the value of this current string is, we are going to
24:04:46
treat this as a root node and then we are going to call the left sub tree and right sub tree. So we are going to create a new tree node called root. So
24:04:54
whatever the current value of the string is, we are going to treat it as a root node. Then after adding the root node,
24:05:00
we are actually going to remove that value. Okay. Now for the left value we are again going to call this uh
24:05:07
recursive d serialized method and that should be it. After this ends basically
24:05:12
we should have a root variable. So we can simply return root. Now from this main method first of all we will have to
24:05:18
create a an array of string where we are actually splitting the string based on the comma that we initially created.
24:05:25
After doing this we are actually going to convert the string array into a list of strings. Now we will simply return
24:05:32
whatever the answer we get by calling this recursive method. That should be it. Now let's try to run this code.
24:05:47
Okay, seems like our solution is working as expected. Let's submit this code.
24:05:53
So I'll be trying to see other faster approaches and see I can uh show make a future video on that. But so far you can
24:05:59
find this code in the comments. So you can check it out from there.
24:06:08
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do binary tree maximum path
24:06:15
some late code problem. And if we see some of the companies where I want to get a job who are already asked this question, there are companies like
24:06:20
Amazon, do dash, Facebook, Microsoft, Google, bite dance, Tik Tok, Snapchat,
24:06:26
Twitter, Apple, Uber and LinkedIn. So that's why I'm paying my utmost attention. I hope you also enjoy the
24:06:31
video. So despite being a hard problem, this is
24:06:37
a very well-liked problem on lead code. Uh basically we are given the root of a binary tree and we need to return the
24:06:42
maximum path sum for that particular non-mpy path. So we will have to understand couple of terminologies over
24:06:48
here. Uh we'll have to understand that what a path sum is and before we understand that we will have to understand that what a path is. Lucky
24:06:55
for us we are given definition of both of them. So a path is a binary tree sequence of nodes where uh each pair of
24:07:02
adjacent nodes in that particular sequence has an edge connecting them. And we are also told one very important
24:07:09
thing that any single node in that sequence can at most appear once. We are also given the note that it is not
24:07:15
necessary that path has to go through the root of the node. Okay. So over here I have drawn couple of different trees
24:07:22
and I'm going to show you some examples of what a valid path is and what an invalid path is. So first of all this is
24:07:28
a valid path and for that we'll have to understand that why this path is a valid path because all the three nodes that
24:07:34
are connected in this particular path they are adjacent to each other. They all have an edge connecting to them and
24:07:40
they all appear at most once and nothing more than that. Now this is also a valid
24:07:45
path and this is also a valid path. This is also a valid path and this is also a
24:07:50
valid path. Both paths are valid as well. And the path that looks like this, this is also a valid path. And the path
24:07:56
that looks like this, this is also a valid path. Now let's see some examples of an invalid path. Suppose I start up
24:08:03
my journey over here. I go up, I go down, I go to the left uh child and then
24:08:08
again I try to go to the right child. Again, this is an example of an invalid path because this node appears twice as
24:08:14
well. Now we know many examples that what a valid path is. Now let's see that what the problem is actually asking us
24:08:19
to solve. After understanding the definition of a path, we are going to understand the definition of a path sum. Basically it is the sum of all the nodes
24:08:27
that are present inside this given path. So that is actually quite simple to understand and the problem is actually
24:08:33
asking us to find the maximum path sum that we can make out of given binary tree. So now I have drawn three
24:08:40
different trees to understand the maximum path sum for each one of them. So first of all for this particular tree
24:08:46
the maximum path sum is going to be this path and why because all the nodes are positive and if we take the sum of these
24:08:52
three nodes it's actually going to be 5 + 4 + 9 which becomes 18 and this is what we need to return in the answer. If
24:08:59
we take the second example things are not as easy as the first one. Why? Because we are dealing with a negative
24:09:05
value over here. So in this case even if we try to do the same path that we had drawn over here this won't work because
24:09:11
the sum of this is actually going to be which is not the most optimal path we can achieve. The most optimal path in
24:09:17
this case is going to be this one with and the sum is actually going to be 5 + 4 equals to 9. And in this case we will
24:09:23
have to return 9. So in this case the maximum path actually is going to be this one between
24:09:30
these three nodes. Why? Though there is a positive value over here, if we were to include this positive value, the path
24:09:38
we would make would looks like this and that would actually go through this root value which has the value of -1 which
24:09:45
actually brings the total path down or total sum down. So that is why it is not in our best interest to include this
24:09:52
node and that is why the maximum path in this case we can achieve is amongst these three nodes where the sum is
24:09:58
actually going to be 10 + 8 + 2 = to 20 and that is what we need to return.
24:10:07
Now before we come up with the optimal solution I'm going to show you few different concepts with various examples. So first of all we have an
24:10:13
example of tree that looks like this where in this case all the nodes are positive which means things are a little bit easy for us and our aim is to find
24:10:20
the maximum product sum we can achieve right. So the idea is at any given portion we have the root information.
24:10:26
Now from this root information what we are going to do is we are going to see that what this left sub tree has to offer and what this right sub tree has
24:10:33
to offer and then addition of all of them should give us our maximum product sum. So in this case this left sub tree
24:10:39
does not have any more children. only has one node which means it can the maximum value it can contribute towards the maximum path sum is going to be
24:10:46
five. So we have the value three already from this root. Then we gain this five from the maximum path sum and then again
24:10:53
we gain this two from this right sub tree. So the total maximum path sum we can achieve is going to be 10 which is
24:10:59
the answer in this case and since all nodes were positive it is in our favor to include all the nodes. So that is one
24:11:05
way to do it right and this is a very simple example so we are able to understand it quickly. Now let's try to
24:11:10
see that what would be the approach in a little bit more difficult uh scenario. So suppose we are given a tree like
24:11:16
this. In this case we actually have a negative value. So if we apply the same logic over here this left subchild has
24:11:24
minus5 to offer. This right subchild has plus2 to offer and this root value is actually three. So maximum path sum
24:11:29
based on the previous logic would actually become zero if we just do sum of all the values. But that is not we
24:11:36
are going not what we are going to do. We are also going to check at any given moment that whether the value that is
24:11:42
being contributed if that is less than zero or not. If that is less than zero immediately we are going to discard this
24:11:49
value which means that we are not going to consider this minus5 to be part of this maximum product sum and in this
24:11:55
case what we are going to do is we are going to do this 3 + 2 because both values are positive. So in this case the
24:12:01
answer we are going to get is five. So we gain one more important thing that whenever we see minus values we are
24:12:07
going to ignore that from our maximum production because they don't add any more value over here. Now one more thing
24:12:13
we need to consider what if we we have multiple nodes and then what should be
24:12:20
our approach in that case. Okay suppose we are given an example like this. In this case what should be our approach?
24:12:26
Well we we want to find the maximum path sum. So again we are going to repeat the same process. We are going to see that
24:12:31
for this root node what is this left sub tree has to offer. It has to offer maximum five value. So we are good up
24:12:37
until this point. For this right sub tree actually we will have to calculate that what is the maximum value it can offer. And how we can do it? We are
24:12:45
actually going to take this root value because that is going to be the part of this right right sub tree for sure. So
24:12:50
we already have value as eight over here. Now from this eight we actually have two options to be included for our
24:12:57
maximum path sum. We can either do 82 or we can do 81. So in this case obvious
24:13:03
choice is going to be two because two this value two is actually greater than with this value one. So in this case we
24:13:09
are going to ignore this one and we are going to keep this two which means that we can do 8 + 2 to be 10. So in this
24:13:16
case we can determine that this actually has the value 10 to give towards maximum
24:13:22
path. Now the question will come to your mind is that why in this case we only
24:13:27
choose value 10 and why not we choose value 11. Well what if in under what
24:13:34
circumstances can this value become 11? It can become 11 if we include all these
24:13:39
three values to be part of this maximum path sum. But we already know that this goes through the root value. Which means
24:13:45
that uh if we were to include all these three values uh to make the value 11, it
24:13:51
won't work because then the path would look like this. It would go from five to three. Okay, so far we are good. Then
24:13:57
again through 8. Now from this 8, we cannot include both one and two because
24:14:03
suppose we try to do it, we include this one and then we try to go back to two. We come up at this eight again and we
24:14:09
know that that cannot be part of a path sum. So that is why we only have the option to choose either one or two. So
24:14:17
that is the important important detail over here. That is why for when we were calculating the maximum contribution
24:14:23
this right sub tree can make we can we only had two options either we could do 8 + 2 or we could do 8 + 1 but not both
24:14:30
of them. So just remember that that is why I showed you this example. So in this case the maximum contribution we
24:14:37
can get from this right sub tree is going to be 10. So now let's calculate the maximum path sum in this case. So
24:14:42
the maximum path sum is going to be the root node is three plus this left sub tree can contribute value five and plus
24:14:48
this right sub tree can contribute value 10. So the answer is going to be 18 and
24:14:53
this is what we need to return in this case. So so far we have understood we had gained very good understanding of
24:14:59
many different cases. Now let's consider one more case where the things become little bit more interesting and why it
24:15:06
becomes interesting because so far we are under the impression that we have to take this root value as part of the
24:15:13
answer. But what if that is not the case? What if we encounter some possibility where this root value does
24:15:19
not need to be part of the main uh maximum path somewhere that we take? Then how do we approach that? So let me
24:15:25
quickly show you an example for that as well. Okay, this is the last complicated example. Now in this case, we are again
24:15:32
going to apply the same logic to find the maximum path sum. But we are going to do some interesting things. So first
24:15:38
of all, we have this root value to be minus three. Right? Now we are going to see that what is the leftmost contribution it can get. It can get
24:15:43
three as as the contribution in this case. Now again for this portion we are going to see that what is the rightmost
24:15:50
contribution it can get. The rightmost contribution it can get in this case is going to be this 8 + 2. So 8 + 2 is
24:15:56
going to be 10 so far. Right? Now if we see over here actually this is not the
24:16:01
most optimal way to approach this. Why? Because this path actually gives us the
24:16:07
maximum path sum. So let's see that how can we actually determine that. Well when we are traversing we are actually
24:16:13
going to have a variable called path to keep track of what is the current maximum value we have found so far and
24:16:20
whether do we need to include a new route. And new root in this case is going to be the condition where we
24:16:25
actually refrain away or move away from the original root we were using because if we were to use this root node there
24:16:33
is no way for us to use all of these three nodes. Uh so that's why we are what we are going to do is we are first
24:16:40
of all going to see that if we use this current root what is the maximum value we are gaining. So the maximum value we are gaining in this case is going to be
24:16:47
three which is this one + 10 which is the contribution we can get from this
24:16:52
right sub tree. So 3 + 10 and let me get rid of this maximum path sum for now. So
24:16:58
3 + 10 plus whatever the root value. So root value in this case is minus 3 which is in this case the total value is going
24:17:05
to be 10. But now when we are traversing or when we were calculating the maximum
24:17:10
contribution we can gain from this uh right sub tree where the root node is
24:17:16
actually eight. The value maximum we can gain from over here is actually going to
24:17:21
be this value 8 plus it has the left its left sub tree is contributing value one
24:17:26
and its right sub tree is contributing value two. So which both are positive values and their total is actually 11.
24:17:33
So this is 11 and this is 10. Then why are we so keen to keeping this root to
24:17:38
be part of the optimal solution? We should not put it in the maximum path sum and we are this is exactly what we
24:17:44
are going to do. Then we are going to choose a new path and this new path the value is 11. So then we are going to
24:17:50
have a maximum path sum variable where we are going to keep on updating the value and we are going to update the value to be 11. And now it does not have
24:17:57
any further no more nodes to check for and then we are going to return this 11 to be the answer. And at any given
24:18:04
moment whenever we find that the new path we are getting that gives us better
24:18:10
answer than whatever the previous answer we were getting then we would update the new path and we will update the value of
24:18:17
the path variable. So that is one tricky part that we have to understand in this question. And now let's see that after
24:18:24
understanding all the concepts now let's see that what would be the way to solve this problem. Uh the idea is uh let me
24:18:31
clean this up a bit. Now I'm going to use the same example to quickly walk through this problem. Uh so first of all we are at this root position. What is
24:18:37
the left contribution we can get? Which is two. The right contribution we can get in this case it's going to be 10. Uh
24:18:43
we actually calculated all of them. Uh now the sum of these two is these three is actually going to be uh 10 only. But
24:18:50
when we were calculating that we had this path variable where we actually calculated the value of this to be 11.
24:18:57
And we updated this path variable. And then we are going to have this maximum path value where we are going to keep
24:19:03
track of the maximum path we have found so far. And in the end because it does not have any more children we are going
24:19:08
to return the maximum path to be uh 11. And this is what the answer we need to return. So basically we are taking a
24:19:17
bigger uh problem and then we are dividing it into bunch of different parts that for this root we are actually
24:19:23
see trying to calculate this left sub tree and right sub tree. Then again for this root value we are again calculating
24:19:29
this left sub train right subrain which means we are solving this problem recursively and that is how we are going
24:19:34
to approach it and also let me show you the time and space complexity. So time complexity in this case is actually
24:19:40
going to be big of n. Why of n? Because at any given moment we will have to iterate over all the nodes that are
24:19:46
present inside this given tree and the space complexity is going to be big of h where h is the height of the tree.
24:19:56
So first of all we will need a separate method called max gain to calculate that what is the maximum value we are
24:20:02
gaining. So for that we are going to create a new method that takes in a node
24:20:08
as an argument. We will also need a maximum sum value. So we are going to
24:20:13
initialize it as global variable and we are going to assign it to the most negative value possible. So okay now
24:20:20
let's start implementing our max gain function. So first of all we are going to have the terminating case that if the
24:20:25
given node is equal to null we will return zero. If that is not the case we will need the values of left gain and
24:20:31
right gain for any any given tree node. So we are again going to call the recursive function for that.
24:20:39
We are going to create a variable called price new path that we are actually going to calculate by using the node
24:20:45
value plus whatever the sum of left gain and right gain is.
24:20:50
Now that is done, we are actually going to calculate the max sum. We are going to compare it with whatever this new
24:20:57
path we are calculating. And once that is done, basically all we
24:21:02
will have to do is simply return uh the node value with whatever the maximum
24:21:08
value is amongst this left gain or right gain. From this max path sum method, we
24:21:14
will have to call this max gain function. So let's do that. After all the calculation, we are simply going to
24:21:20
return whatever the max sum we are able to achieve. Okay. And now let's try to run this
24:21:26
code. Seems like our solution is working as expected. Let's submit this code.
24:21:34
And our solution is actually pretty efficient and faster than lot of other solution. And I will be posting this in
24:21:40
the comments so you can check it out from there.
24:21:52
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today actually we are going to learn about a
24:21:58
new data structure and we are actually going to learn to implement a try or a prefix tree. And if we see some of the
24:22:03
companies where I want to get a job who already asked this question there are companies like Amazon, Google, Twitter, Microsoft, Oracle, Apple, Facebook,
24:22:10
Goldman Sachs, Uber and Bloomberg. So that's why I'm paying my utmost attention. and I hope you also enjoy the
24:22:15
video. So this is a lead code medium problem and basically we are going to implement
24:22:21
a try over here or a prefix tree. So first of all in the problem statement we are given the definition that what a try
24:22:27
is and actually I'm going to show you very eloquently that what a try is and how it works. But let's understand the
24:22:34
definition first. Basically a try is a prefix tree which is a tree data structure that is used to efficiently
24:22:40
store and retrieve keys in a data data set of strings. Uh there are bunch of
24:22:45
different applications of this try data structure and I'm going to go over all the applications soon as well. Now if we
24:22:51
see that what is needed in this problem basically we need to initialize a try object first of all then we need to
24:22:58
create three different methods which are mentioned over here. So first method is the insert method which does not return
24:23:05
anything and basically we are only given the input as a string word and we need to insert this word in inside this new
24:23:12
try object that we are initializing. After doing that we could be given a search method where again as an input we
24:23:19
are given a string called word and we need to return true or false which means that whether if this word exists inside
24:23:25
this try object that we have created we need to return true otherwise we need to return false and there is also one more
24:23:31
method where again we are returning true or false uh and the name of method starts with where we are actually given
24:23:38
a string and the name of the string is prefix but basically we need to check that whether this prefix
24:23:44
actually exist as a part of any existing word inside this try object and if that
24:23:50
is the case we need to return true if that is not the case we need to return false so here is an example that we are
24:23:56
given so suppose we are given as an input where actually uh first of all we
24:24:01
are creating the try we are inserting this inserting some word we are searching for some words we are doing
24:24:07
the start with operation and uh this is the explanation so basically we initialize the try object as mentioned
24:24:14
then first of all we insert the word apple. So okay so currently apple exist over here. Now again we search for that
24:24:20
whether apple exist or not and because it exist we return true as the answer. Again we search for with the word app.
24:24:26
But thing is remember so far we have only inserted the word apple. App does not exist as a whole word. So that's why
24:24:33
we we return false. Again we search for starts with method for this word app.
24:24:38
And remember because this apple this app is actually a prefix of this apple. So we return true in this case and so on
24:24:45
and so forth we can do bunch of different uh operations. So this is what is needed. Now let's understand what a
24:24:51
try is. Okay. So first of all let's try to understand that what a try actually is.
24:24:58
Basically a try is a treel like data structure but it's a little bit different and a different variant of a
24:25:03
tree. Now if we know for any single tree the basic properties are that every single tree has a root node. Now this
24:25:08
root node has some subsequent children nodes. There could be any number of different childrens and those children can have some children of their own and
24:25:15
their links actually fi found some meaningful relationship. So that is what we are going to use uh to generate this
24:25:22
try but we are actually going to generate this try to store different string values per character that is the
24:25:29
important property per character. So it makes us easier to understand or find different words or different strings and
24:25:35
there are a number of applications of a try. Let's try to understand try with some example. So first of all as any
24:25:41
different tree we are actually going to have a root node right now suppose for this root node what we are trying to do
24:25:46
is we are of course we are trying to add some different string value. So let's take a string value. Suppose the first
24:25:52
string we are trying to add is the actually the word uh fang. So if we take this word fang first of all we will have
24:25:58
to add the word f because remember I already told you we are going to do it character by character. Then we will add
24:26:04
a a n and g we are going to add it in this sequence. So in order to do that logically speaking for this root root is
24:26:10
going to remain common. But thing is first word we will have to add is van. But the thing is first we will check
24:26:16
that whether is there any children of this root node which is actually f. If that is the case we are actually going
24:26:21
to leverage that. But this does not have any children. So if this does not have any children we are actually going to create a new children f. Now again with
24:26:29
this f there is no children that is a. So again we are going to create a new children. Then again we are going to
24:26:34
create a new children and then we are going to add the values of n and g as well. After adding this we have actually
24:26:39
created a root inside this try data structure which represents this word
24:26:44
fang that we were originally trying to uh create. After creating that we will have to find some way to identify that
24:26:51
this fang word has actually ended. So what we are going to do is we are actually going to create a special character or a special node over here
24:26:58
which we are going to denote as an end node which defines that the word has actually ended over here. Right? After
24:27:04
doing that let's try to add one more word. So suppose rather than fang we are trying to add the character mang. So
24:27:10
let's try to again add mang over here. Now for this mang first of all we are going to check that whether this m exist
24:27:16
as one of the children of of this root node. So m is also no children. So first of all we are going to add m and then we
24:27:23
are going to add subsequent characters and we are going to link them with this uh path. After that in the end we are
24:27:30
actually going to add a special character and denote that the word has actually ended over here. So let's do a
24:27:35
quick recap. Basically what we have done so far is we have actually created two separate branches where if we go depth
24:27:42
first search diving in those branches we would actually find those subsequent words uh in those particular branches.
24:27:49
So it makes uh pretty efficient for us to identify any string and to see that
24:27:54
whether it exists or not and predict that what the person is going to copy. Now suppose we are I'm trying to add the
24:28:00
next word fan. Now for the adding this next word fan what we are going to do is first of all we are going to check f
24:28:05
exist or not. So f exist over here. So because f exist we are actually going to leverage that. So now we are not going
24:28:11
to add any entry over here. Again this a also exists as one of the children of f. So again we are not going to add any any
24:28:16
entry over here. Now this n so n is not a children of this original a. So we are
24:28:22
actually going to create an entry over here. So we we will create an entry over here uh and we are actually going to
24:28:28
name it as n. And now since this word ends over here we are actually going to create this end node over here. So again
24:28:34
remember if we go depth per search in this direction we will actually be able to find this word fan and that is the
24:28:41
whole purpose of a try. Now let's try to add one more word uh which is men. Oh
24:28:47
sorry m a ma. So if we try to add this word ma. So first m also exist over
24:28:53
here. A also exist and a also exist. So because these three exist we are actually not going to break this link
24:29:00
and create this end word over here or we are not going to do that. uh actually we
24:29:05
are going to keep this as it is because this m aa is actually a prefix of this
24:29:10
original word mang that we have already added to our try and that is why a try is also called a prefix tree. So now the
24:29:18
word makes sense that why a try is called a prefix tree and basically this is what we are trying to implement.
24:29:24
There are a bunch of different applications of a try and let's see some of the applications that are really cool in real life real life world.
24:29:32
So before we start implementing the method first of all let's understand that what are different applications of a try. So applications like autocomplete
24:29:39
where you type something and it automatically gets completed or understood by by that particular product. Uh that is implemented using
24:29:46
try. Uh so features like Google Chrome, Amazon where you try type few words and then it automatically understands that
24:29:51
what you are trying to do and automatically gives you the answer. Uh that is implemented using that. All the spell checks or all the dictionary
24:29:58
related mechanisms they are also implemented using some versioning of a try. Games like word search, word
24:30:03
puzzle, word, they are also implemented using a versioning of word try and uh
24:30:08
features like predictive text search or expected text search that you type something it automatically expects that
24:30:14
what could be the next potential words. You typically you see that in YouTube, Google all the time. Uh they are also
24:30:20
implemented using tries. So these are only few but very powerful uh applications of a try and there are
24:30:26
hundreds of them. I haven't mentioned them. So that's why try is important to understand. Now let's move back to our
24:30:32
question and start implementing those three methods.
24:30:39
So first method they are asking us to implement is an insert method where we are not returning anything but we are
24:30:45
inserting different strings into our try. So for this example we are actually going to implement these four different
24:30:51
types of strings into our try and uh we will see that what would be the logic behind it. Now as mentioned earlier that
24:30:57
every try actually has a root node. So again with our try we are also going to have a root node. Now from this root
24:31:03
node the idea we are going to use is that whatever string we are trying to insert first of all we will check that
24:31:08
whether the first word that we are trying to implement or the first character we are trying to implement if that is present as one of the children
24:31:14
of the existing uh root node or not. If it is children of that particular root node, we would keep on branching for
24:31:20
that particular uh child and keep on updating the number of characters that we are trying to implement. If it does
24:31:26
not exist, we will actually create it uh create a new node or a new branch and we will add that entire word into that
24:31:31
branch. Now, as mentioned earlier, the moment we reach to the end of that particular node, we will actually have to create an end node to denote that
24:31:38
this word actually ends over here. So, let's start implementing what is being asked over here. So, first we are trying
24:31:43
to implement the word apple. So, a does not exist as any of the children of this root node. Currently, it has no
24:31:49
children. So, we will have to create a new node. So, first we are going to create a new node for apple. Okay. So
24:31:54
let me create a new node A and then I will keep on appending all the remaining characters and after adding all the word
24:32:01
because this word ends at this E I'm actually going to create a special node and I'm going to denote it as an end
24:32:07
node. So that say that is to for us to understand that this word actually ends over here and we don't need to move any
24:32:13
further. Okay. Now next word we are trying to implement is G. And also remember one thing I forgot to to tell
24:32:19
you that this root can have potential 26 different children. Right. uh and this
24:32:24
26 different children can have 26 different children of their own. So the mechanism we are going to implement to
24:32:29
find that whether a node contains any particular children or not is actually going to be used based on some key value
24:32:35
mechanism and because it's a key value mechanism uh the whole operation of searching that whether any node or
24:32:42
anything if that is a part of any children of that particular node or not that is being done in constant time. so
24:32:48
that it helps us understand uh helps us to maintain the uh consistency and speed of our data structure. Now let's move
24:32:55
back to adding the word Google to our try. So for the word Google we do not have any uh children that is starts with
24:33:02
G. So we are also going to create a new node over here or new branch over here where first character is G and then we
24:33:10
will add all the remaining characters. As previously mentioned at the end of the word we are going to create an end
24:33:15
node. Okay. Now things become little bit uh interesting with this word Amazon. So
24:33:21
for this word Amazon when we start checking that whether this a is a children of this root node or not we
24:33:26
find that a is already a children. So we will keep on updating the value over here that okay we have already find a
24:33:33
word or a character that is already a children and then we will keep on moving to the next character. So first this a
24:33:39
is already present so we ignore that. Now next character we will we want to find is m. So for this M we will try to
24:33:45
see that whether this A contains any children that starts with M. But the thing is currently this A only contains
24:33:51
one children that starts with P and not M. So we will have to br create a new branch over here. So let's create a new
24:33:57
branch. So new branch starts with M. And then we will add all the remaining word characters over here. Okay. And now the
24:34:04
the next word we are trying to implement is amazing. For the amazing uh okay we already have a children of this root
24:34:10
that starts with a. So we have taken care of this. M is also present as one of the children. Okay. Now A is also
24:34:16
present as one of the children of this M. Okay. So that is that is also good. Now this Z is also present over here.
24:34:22
Now for this I I is actually not present as one of the children of this Z. So we will actually create branch over here uh
24:34:30
that starts with I and then we will add this N and G over here and in the end we
24:34:36
will create or we will add the end node over here. And now we have actually inserted these four characters as or
24:34:43
these four strings into our try. And if you see uh we can find each one of them
24:34:48
by going in DFS motion in any particular branch. So first of all this gives us
24:34:53
the value Google this gives us Apple this gives us amazing sorry Amazon and
24:34:59
this gives us amazing. So that is how tries typically work.
24:35:06
Now let's move on to the next method that is being asked.
24:35:12
So for this search method for our try, we will be actually given a word as the input and we will have to check that if
24:35:19
that word exists inside our given try, we will have to return true. If it does not exist, we will have to return false.
24:35:25
So let's start implementing the same method and actually we are going to use the same try that we have create we have
24:35:30
created. Okay. So let's use the same try that we have created earlier and we will try to see that whether these four
24:35:36
strings uh do they exist inside this given uh try or not. So let's understand the logic behind it. Uh well if the
24:35:43
string exist basically all we will have to do is first of all we will check that okay whether the first character if that
24:35:49
is the one of the children of this root node or not. If that is the children we would keep on checking its children for
24:35:55
this next subsequent words and try to complete this entire word. If we are able to complete this entire word
24:36:01
without this uh try breaking or not able to find the children if we reach to the end we can conclude that this word
24:36:08
exists. If we cannot come to the end we will conclude that this node does not exist. So first of all let's try to see
24:36:14
in this example. So for the first word is a. So a exist over here as one of the children. So we will ignore this one.
24:36:21
Now next word is m. m also exists. So we will again ignore this one. The next word is a again this word exist. Now z i
24:36:28
n g uh they all exist in this particular fashion. So this word amazing exist
24:36:33
inside this given try. So because it exists we will return true as the answer in this case. Right? Now let's try to
24:36:39
search for this word good. Now for this word good the first character is G. So first character is G present over here.
24:36:46
So okay we are good up until this point. Next character is O. O is also present. Again O is also present. So we can
24:36:51
ignore first three characters of this good. Now for this next O, we do not have a children that starts with value
24:36:58
D. So because of that uh we do not have any new branch over here that starts
24:37:03
with D. So we can actually conclude that the word good does not exist in this case. And uh because it does not exist,
24:37:11
we will return false over here. Okay. Now let's try to search for the word Googler. So again for this word Googler,
24:37:18
okay, G also exist, O exist, O exist, G exist, L exist, and E exist. Okay. Up
24:37:23
until this point all the words exist but when we try to search for the next word we actually encounter that okay this is
24:37:29
the end node of our try or of our uh DFS search for this particular direction. So
24:37:34
because it is the end word we will actually return false over here because this word has not been completely
24:37:41
searched because it does not exist inside our try and we are actually able to do it pretty quickly and pretty
24:37:46
efficiently. Okay. So now next word is app. So let's try to see that whether this word app exists inside our uh try
24:37:53
or not. So first of all we check for this word a. A exist over here. Then this word p also exists and p also
24:37:59
exists. Right? So we are good up until this point and our mind will say that okay because this word exist we need to
24:38:05
return true. But thing is that is not the case. The idea we are trying to do in this search method is that we are
24:38:11
trying to see that whether the whole word that is given as the input exist as only a word inside this given try. But
24:38:19
for this app, if we try to see the next node, the next node is actually the SL L and E. So there are still some
24:38:25
characters that exist inside this given uh DFS path that we are traversing and
24:38:31
the next node is actually not the end node. So because the next node is not the end node and there are still some
24:38:37
more nodes that exist, this app is actually a prefix of original word apple
24:38:43
but not the whole word as it is. So that's why in this case we need to return false as well. And this is the
24:38:49
important thing that is differentiating between this method search method and the next method we are going to
24:38:54
implement. Now if we see the time and space complexity in this case the time complexity for this method is actually going to be we go of n where n is the
24:39:01
number of uh characters that are present that we are trying to search in any given word. If we see space complexity
24:39:07
for the space complexity we are actually not using any additional space. So that is going to be the constant space complexity for this case which is pretty
24:39:14
efficient in my opinion.
24:39:21
So now let's understand our starts with method and we are also going to use the same try that we have created before
24:39:26
right and we are going to s see that whether the the words that starts with these characters are they present inside
24:39:33
our given try or not. So again this is very similar to the search method uh where we are going to iterate over word
24:39:39
by word or character by character for any given word and we will see that whether that is present inside our try or not. If that is present, we can
24:39:46
return true. If that is not present, we will return false. So let's see that in action. So first of all, we have this
24:39:52
character A. So A is already one of the children of this root node. So okay, we are good up until this point. Then we
24:39:57
have M. M is also a children over here. And then we have A. So A is also a children of this one. So we can conclude
24:40:03
that because this word ended, we do not have any more n things to search for. And all of the characters they were
24:40:09
present inside this given try. We would actually return true. In this case they saying that the word that starts with a
24:40:15
m a is actually present as one of the uh children or one of the branches of this
24:40:20
tribe. Now let's try to search for this word a pk. So a exist and p exist. But
24:40:26
thing is for this p we do not have any children that starts with k. So because of that this k is not present. Uh we can
24:40:32
actually return false in this case saying that we do not have a word that
24:40:37
starts with ak as the prefix inside our try. And remember because we are
24:40:43
searching through prefix that is why this is also called prefix tree. So yeah mind blown right my mine as well. Now
24:40:50
let's try to search the word good. Well there is Google but there is not good but I think is Google is pretty good.
24:40:55
Yeah. So that's why it's one of my dream companies but let's try to search that. So okay this is go o. So go o is present
24:41:02
over here but this d is not present as one of the children of this o. So because of that we will also return
24:41:07
false in this case. Okay. Now we have this word apple. So apple is actually
24:41:13
the entire word that is present over here. And if you look at it, we do have a word that starts with the word apple.
24:41:20
Even though it ends at apple, well the thing is also it starts with apple, right? So and the name of the method is
24:41:26
actually starts with. So why don't why should not we return true in this case. So this will also become true that okay
24:41:31
word that starts with apple is present inside our given try. And that is the logic we are going to use to implement
24:41:37
the starts with method. Again very similar to the search method just a little bit different variations. Uh now
24:41:43
if we try to see the time and space complexity in this case the time complexity is also going to be bigo of n
24:41:48
that is where n is the number of characters that are presented inside any word that we are trying to search. If we
24:41:53
see space complexity the space complexity is also going to be bigo of uh one or constant space complexity
24:41:59
because we are not storing anything in our text tag. So this problem is asking us to implement insert, search and
24:42:05
starts with method. But before implementing these three method, first of all we'll have to define that what a
24:42:11
try node is. This is only a try class. So I would be creating a separate class
24:42:16
called try node. Now in this try node class first of all let's go over some basic methods that we are going to use
24:42:22
that will enable us to do lot of things. First of all, we have defined a finite number of cases R which is 26 because
24:42:30
any single node can only have up to 26 distinct children because each children
24:42:35
represents a character inside the alphabet. Now uh every single try node has a certain set of links and links are
24:42:42
defined by the children of that particular node. Uh we also created some more methods. So let's go over them. So
24:42:49
one method is contains key method where we pass in a character and we get the answer that whether any particular link
24:42:56
or any particular node does that contain that particular character as one of its children or not and we can get the
24:43:02
answer in a constant time complexity because remember we are using array indexing uh and the in maximum
24:43:09
possibility of indexing can be 26 and we can get the answer immediately. Same we are uh we have a method get where we
24:43:16
provide the character and we get the answer that whatever the value of that particular character is inside any of
24:43:23
the children of any tri node. We also have a method put where we provide the value of a character and the node we are
24:43:29
trying to put it as and we also have set end and is end method. uh that is to
24:43:35
define that whenever we run out of uh words that we need to put in in any single try block or any single try
24:43:41
branch uh the last node is going to be is end node and we will mark its value
24:43:47
to be true. Uh so now let's start implementing the try node. So first of all we will be we will have to create a
24:43:54
try node uh root. So let's do that. Now since we have our root node, first of
24:44:00
all for this public try method we are going to initialize the root. After doing that first of all let's start
24:44:07
working on our insert method. So for our inst insert method we are going to have
24:44:12
a root node. Now we are going to iterate over the given input word. We will
24:44:17
define that what is the current character we are at. Now first of all we will have to check that whether the
24:44:23
given node we have if that contains that uh particular key or not. So if the
24:44:29
given node does not contain that key we will actually have to create a new entry over here. So we will use our node.put
24:44:35
put uh method and inside that we are going to pass in the value of the current character and we are going to
24:44:41
pass in the we are going to create a new try node for that and then we are going to update the nodes value and once this
24:44:48
loop ends basically the last node we are at we will have to set its value to be the end node. So we are going to mark
24:44:55
its value to be the set end value and uh which would basically so it defines that
24:45:00
this is the last node. Uh before we work on the search and starts with method, remember both search and starts with
24:45:06
method, they are pretty similar to each other. So we are actually going to create a supporting method uh called
24:45:12
search prefix. Once again we are going to initialize the node to be the root node. And now we are going to iterate
24:45:19
over the given word. So now we are going to check that if the current node does
24:45:24
it contains the given character or not. If it contains the given character, uh
24:45:30
we can actually uh set the value of node. If it is not present, we simply need to return null. And that's it. And
24:45:37
if we somehow reach to the end of this loop, we can simply return whatever the node we have we are at. Now uh from this
24:45:45
our uh search method basically what we are going to do is first of all we are going to initialize our try node and we
24:45:52
are going to pass in the value of the word. Now we simply have to return that whether the current node we get in the
24:45:59
return and if it is not null and it is end we can simply return true and same
24:46:04
thing we are going to do for our starts with method. So again for our starts with method we are again going to call
24:46:11
the search prefix method and uh basically all we will have to check that
24:46:17
whatever the return value we get if that is not equal to null. If that is not
24:46:22
equal to null, we can simply return true. And uh that should be it. Let's try to run this code. Okay, seems like
24:46:29
our solution is working as expected. Let's submit this code.
24:46:34
And our code runs pretty efficiently compared to lot of other solutions and it is also very uh much efficient in
24:46:40
terms of space complexity. The thing is I was not able to come up with this solution on my own. I actually had to
24:46:46
use a lot from the solution tab. So I just want to make it clear. Uh so yeah, everyone has to go through it and uh I
24:46:54
will be posting this in the comments so you can check it out from there.
24:47:07
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do word search to lead code
24:47:13
problem. And if you see some of the companies where I want to get a job who have already asked this question there are companies like Amazon, Uber,
24:47:19
Microsoft, Google, Snapchat, Facebook, Apple, Twitter, Tik Tok, Bloomberg,
24:47:24
Spotify, Twitch and Airbnb. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
24:47:31
So this is the lead code hard problem and basically we are given an M crossN matrix of characters now and we are also
24:47:37
given a different list of string called words. Now we need to return all the words that are present on the given
24:47:43
board. We are also given one more thing that each word must be constructed from the letters that are adjacent to each
24:47:50
other. So and we are also given the definition that what adjacent cells are. Basically any cells that are horizontally or vertically neighboring
24:47:56
to each other. We can consider them to be a part of the consecutive sequence series and we can use them to create
24:48:02
words. So let's try to understand this with an example over here. Over here we are given a 4 + 4 matrix and for this
24:48:08
matrix we are told that these these are the list of words we need to check that whether they are present inside this given matrix or not. So if we try to
24:48:16
just look at this example basically we can see that this first word oath is actually present over here where O a t
24:48:23
and h they are uh creating or forming this word and if you see they are all
24:48:30
sequentially adjacent cells to each other. So that's why we can use them to form this words and see whether it's
24:48:36
present or not. So in the answer first of all we are going to add the word oath uh as one of the answer. Then if we look
24:48:43
at the answer we can also find this word uh eat to be present. So e a t that is
24:48:51
present in this manner. And again though this is on the left side. This is not the conventional way to write it. But
24:48:57
still based on the adjacent cells we can actually form this word eat. And that's why this eat is also going to be part of
24:49:03
the answer. So we will add eat in the answer as well. Now for this two P E A P and drain these two are not present
24:49:10
inside this given matrix. So we will not include them in the answer. And this is the answer we will have to return. So
24:49:16
basically it is one kind of a word search game or word search puzzle. So that is why the name is word search 2
24:49:22
and this is the little bit of advanced version. So first we'll see that what is going to be like a basic very trivial
24:49:28
approach and then we will try to improvise using uh different set of data structures.
24:49:36
Okay. So most basic idea we are going to have is that we will start iterating over all of the characters that are
24:49:41
present inside this M crossN matrix and then for every single character we are going to see that whether that matches
24:49:48
with any of the starting words or not. If we find a potential match, then we will try to find the subsequent
24:49:54
character and the neighbors of that particular character to see if we are able to generate any exact word or not.
24:50:00
And the moment we do that, we will actually put it in a new variable called answer. And that is how we will be able
24:50:05
to generate our answer. So let's try to see this in action. So first character in this case is X. So X matches with
24:50:11
this character over here in the in the given set of words. So next we will have to see that whether any neighbor of X is
24:50:17
actually Y or not. Neighbor of X is actually H and A. We do not find Y over here. So because we do not find Y over
24:50:23
here, this X does not lead to anywhere. So okay, we can mark this as visited. That does not lead to any answer. Next
24:50:29
character is H. So H matches with this first character. Uh and then we will have to see that whether B exists as one
24:50:34
of the neighbors of H and B also exists as one of the neighbors of H and then the subsequent character O also exists
24:50:40
as one of the neighbors of B. So in this case this HBO is actually a complete
24:50:45
word we are able to make based on subsequent characters that are pro present adjacent to each other inside
24:50:51
this given matrix and because of that we are going to create a new variable called the answer and in the answer we
24:50:56
are going to add the the value hb over here. Now we will start iterating over this a. So again a is the starting point
24:51:03
over here and next character b and c we are able to generate this pair using subsequentially iterating over and uh if
24:51:10
we see over here we can also generate this a bc in this fashion. Now this character is y. So again y is not part
24:51:16
of starting character of any other word. So we cannot do anything about this. Uh next character is again c that we have
24:51:22
already visited. So we don't need to visit this. And next character is z. Z again is not the starting point of any of these characters. So in this case
24:51:28
this is the answer we will we are going to have and we we can return this one. This solution works as expected. There
24:51:34
are no issues with this one. But if you just see we only have a 3x3 matrix and
24:51:39
for every single character in the worst case scenario we might have to iterate over every single word uh and check that
24:51:46
whether it matches the starting word or not. We can maybe simplify using a hashmap. But the thing is this is still
24:51:52
going to lead to a very bad solution in terms of time complexity. This is going to be disaster for because for every
24:51:59
single character we might have to iterate over every single word that there is and uh once we find a match
24:52:06
then we will have to iterate over all the neighbors of that particular character as well. So that leads to nowhere. So let's try to see that where
24:52:13
we can find a better time complexity and uh the solution to achieve a better time
24:52:19
complexity is actually using a new data structure called try. Now I have already extensively worked on try and you can
24:52:25
find all of those solutions over here. Uh check out this video if you want to learn that what a try is and what are
24:52:31
its applications. Now let's see that how we are going to use try in this case to improve our uh performance.
24:52:40
Okay. So the previous example we see basically what we are doing is we were iterating over every single character
24:52:45
and then we were trying to see that whether that character matches the first element or not and sequentially we will
24:52:50
have to check every single word that was present and if we find a potential match then we will have to check all the
24:52:56
neighbors to see if the next consecutive element is present or not and that was the major reason that why we were having
24:53:02
a disastrous time complexity. So in order to improve that if we can find
24:53:07
some way to eliminate this uh checking procedure that for every single character we might have to look up all
24:53:13
the elements or all the words that are present because imagine if there are million words present we might have to
24:53:18
check million times and then that is going to be very disastrous. Uh the idea we are going to use is that whatever the
24:53:24
words that we are given, we are actually going to convert these into a try and
24:53:30
because we are converting them into a try for any character searching that whether it is the starting point of any
24:53:37
word or not becomes pretty easy for us and we can actually do it in nearly constant time. uh because in the try it
24:53:43
is very fast and efficient to find that whether any word exists or not and if it exists uh it is very easy for us to
24:53:50
iterate over that particular word or not. So first of all let me quickly create a try block based on these three
24:53:55
words uh the try block is going to look like this.
24:54:00
So based on the words that we were previously given we actually created a try block and now using this try block
24:54:06
we are going to make things pretty easy for ourselves. Basically we are going to iterate over in the same fashion for the
24:54:13
given matrix. But this time we all we will have to see is to look up in this try that whether the current character
24:54:20
if that is any children of this given root node or not and if that is the case we will keep on iterating. So first we
24:54:26
find this character to be E. E is not part of any children. So we can we can ignore that. Next one is F. F is
24:54:32
actually part of a children. So okay now we have found F to be part of the children. Now we will have to see that
24:54:37
what is the next character in the in this uh try block. So this next character is a. So we will have to see
24:54:43
that whether any neighbors of this f is actually a or not. So we are we will have to check on three sides and we find
24:54:49
a match over here that this is a. Okay. Now again next character is a. Again this neighbor is actually a. Okay. Now
24:54:56
this character is n. So again neighbor of this a is n present over here. And again the next character is g. So g is
24:55:03
also present over here. And since we have reached to the end node inside our try because of that uh we can conclude
24:55:10
that the whole word was actually present inside this given uh matrix and we can
24:55:16
return true in this case and we will add it to our answer list. So inside the answer list the first word we are going
24:55:22
to add is fang that uh is present inside this given matrix. So see how easy it is
24:55:28
for us to find this these things and okay now the next character is R. R is not children of any of these root nodes.
24:55:35
Uh next one is T. T is also not a children. L is not a children. These these are all visited. Now this G. G is
24:55:42
actually a children. So now it becomes easy. Now we will have to start iterating over. Okay. So we are at this
24:55:48
position G. Now the next element is O. O. The next element is O. And O is also
24:55:54
a neighbor over here. Okay. So which is good. Now the next element is O. Again O is a neighbor over here. So which is
24:56:00
good. Now this next element is G. G is also a neighbor of this O. Right? So we
24:56:05
are good up until this point. Now we have to find this L. Now if we look at this G, we do not find L to be a
24:56:12
neighbor of this G. So because of that we will actually have to roll back and
24:56:17
we cannot move forward with this path. So now we will be have we would have
24:56:22
visited this G and we that did not lead us to anywhere. So again we will start with our routine uh procedure. Okay. Now
24:56:29
this next character is O. O is not starting point of anything. T is also not starting point of anything. G is we
24:56:36
can we already used it. Now this is again G. So again G is a starting point of this one. Next character is O. O is
24:56:43
present over here. Next character is O. O is also neighbor of this one. Next character is G. G is neighbor of this
24:56:48
one. Next character is L. L is neighbor of this one. And next character is E. E is the first character. And because we
24:56:55
reached to the end character over here, we can conclude that Google is also present inside this given matrix and we
24:57:00
will add it to our answer. So we will add one one other entry called Google. Okay. And now next uh again this
24:57:06
character is L. So L does not lead to any children of this root node and F does not lead to any children of this
24:57:12
root node. So in the answer we are going to return this fang and Google to be the
24:57:17
answer and this this would be the most optimal way to solve this problem. Remember because we used a try block it
24:57:24
things becomes much more faster for us and we can immediately look up that whether any single character that leads
24:57:30
to an answer or not. Okay. Now let's do the tricky part. We will have to do the time and space complexity analysis. So
24:57:37
for the time complexity analysis it's actually a little bit tricky. The first thing that is a given fact is that we
24:57:43
will have to iterate over every single character that is present inside this given M crossN matrix. So that's a given
24:57:49
fact. Suppose that the total number of cells that are present are actually m. So now okay we already know that that is
24:57:55
whatever the time complexity is going to be the factor of m. Now for this particular m imag imagine that for any
24:58:01
particular character what is the maximum work we will have to do in the worst case scenario. Well the maximum work we
24:58:07
can do have we will have to do in the worst case scenario is that any particular character suppose this f is
24:58:13
this f matches this character that is present. Now for whenever we find a potential match we will have to look for
24:58:20
the next element in all three directions of that particular word. So suppose this O has we was a potential match we will
24:58:27
have to iterate over all four directions in any given case. So for any single cell we might have to iterate over in
24:58:33
the all four directions and for all four directions the number of traversal that
24:58:39
we will have to do for each one of them would depend on the next three or the
24:58:44
next remaining three characters. Because remember for this Google suppose we find a match this O to be a match. Now the
24:58:51
moment we find this O to be a match again we find this O to be a match. So now because we find this to be a match
24:58:58
we do not have to look for this particular element we will have to look at the remaining three positions. So
24:59:04
then we will have to for any single character we will have to look in the four directions and for all the
24:59:09
subsequent elements we will have to look in the remaining three directions and that we will have to do depending on the
24:59:16
length of that particular word. So for the remaining three elements we will have to iterate over to the length of
24:59:22
that. So that's why 3 to the power of L minus one. And why minus one? Because
24:59:28
for this first character we are actually looking looking in the worst case scenario in all four directions and for
24:59:35
all the subsequent length parameters. So suppose for this particular fang for
24:59:40
this F we might have to look in four directions and for this A we only have to look in the remaining three
24:59:46
directions because one adjacent cell is already F. So that we we do not have to look at. So this is going to be the time
24:59:53
complexity. So if I write the final time complexity, it's actually going to be big of m into 4 * 3 to the power of l
25:00:02
minus1 and that is the final time complexity. This is a very difficult time complexity analysis. Uh so yeah it
25:00:09
gives you an idea that why this problem is pretty popular. If we see space complexity that is pretty simple. Space
25:00:14
complexity depends on the total number of words that are present. So suppose we sum that up to big of n where m is the
25:00:20
total number of characters that are present in the initial word list. Uh so after doing this time and space
25:00:26
complexity analysis now let's move on to the coding.
25:00:32
Before we implement our solution we are actually going to create our class try node. In the class solution we are going
25:00:39
to define couple of global variables. Now inside the find words method. First of all, we are going to initialize our
25:00:45
try block and we are going to add all the words to our try block.
25:00:51
After creating the try node, now we are going to start working on backtracking uh starting with each cell in the board.
25:00:58
So first of all, let's create uh the board variable. And now we are going to initialize couple of loops to iterate
25:01:04
over this full board uh matrix. So now for every single position inside
25:01:10
this given matrix we are going to check that whether that is actually any of the children of this root try node that we
25:01:17
have created and if that is the case then we will create a helper method called backtracking where we are going
25:01:23
to iterate over the all the adjacent cells of that particular row and column position and also uh that particular
25:01:29
entire DFS traversal for that particular uh branch inside our try node. And after
25:01:35
this loop ends, basically we should have populated our answer inside this answer
25:01:41
uh variable that we have created. So we can simply return that.
25:01:47
And now let's create our backtracking method. So this is going to be our recursive method. First of all, we are
25:01:54
going to define couple of variables. First of all, we are going to check that whether the current node is actually a
25:02:00
word or not. If that is a word, we can immediately add it to a result. Okay, if that is not the case, we will
25:02:08
have to start doing our traversal. So, how we are going to do our traversal? Remember, whatever the current row and
25:02:14
column is, we cannot use the same word again. So, we are actually going to mark this as hash in a way for us to identify
25:02:21
that uh that is the node we have already visited. Now, for any given row and
25:02:27
column, we will have to iterate over all of its neighbors. So, we are going to use couple of variables to our
25:02:32
advantage. Now with the help of row and column offset it becomes pretty easy for us to
25:02:37
iterate over all the neighbors of any given node. So now we are going to run a for loop and we are going to iterate
25:02:43
over all the neighbors of given row and column position. First we check that whether our new row
25:02:50
and new column if they are going out of bounds or not. That is the case we just simply ignore that. Otherwise if we are
25:02:56
at the correct neighbor we need to check that whether that neighbor is actually subsequent character uh that we have
25:03:04
already stored in our try or not and if that is the case we are going to call our backtracking method again. So now
25:03:11
our after our exploration ends basically we will have to put back this hash to
25:03:17
its original position and that should be it. There is one more optimization we
25:03:22
can we can do and that is to incrementally remove the leaf nodes which means that whenever we identify
25:03:28
that the current nodes children if that is empty then basically we can just remove that from our parent that should
25:03:36
be it. Let's try to run this code.
25:03:45
We'll also have to update the value of the node in the else condition. Okay, seems like our solution is working
25:03:51
as expected. Let's submit this code
25:03:56
and our code runs pretty efficiently. I will be posting this in the comments so you can check it out from there. Thank you.
25:04:11
Hello friends, we are not employed by a fang company. So let's not complete coding till we get there. Today we are going to do design add and search words
25:04:18
data structure lead code problem. And if you see some of the companies where I want to get a job who have already asked this question there are companies like
25:04:24
Amazon, Google, Microsoft, Apple, Facebook, bite dance, Twitter, Uber and Lyft. So that's why I'm paying my utmost
25:04:31
attention. I hope you also enjoy the video. So this is a lead code medium problem
25:04:37
and as the name suggests that we are actually designing a data structure where for this data structure we have to
25:04:42
support that we can add new words to this data structure and if given any string we we can actually find the
25:04:49
previously added words or strings as well. So we are being asked to implement the word dictionary class. Now in the
25:04:55
word dictionary class first of all we'll need to initialize the word dictionary object and then we need to create two
25:05:00
different methods. First method is add word method that that takes in a string word as an input being done. It adds the
25:05:07
word to our data structure um that we can use to match it later. And then there is a boolean method called search
25:05:13
where again we provide a string word as an input and that returns true or false if that word has been previously added
25:05:19
or not. Uh we are also given one one more condition that for the search method there could be dots provided as
25:05:26
inputs where we can conclude dot to be any letter. So if we are given the word something like bad that is already
25:05:33
already being added and then we are asked to search for the word using B do D. Uh actually these two words we can
25:05:40
consider same because this dot we can consider it to be a. So let's try to understand this with an example. Uh over
25:05:46
here we are given a bunch of different add word and search word mechanisms and
25:05:51
uh this is the explanation provided. So basically first of all we initialize the object word dictionary. Now for that uh
25:05:58
first we add the word bad, dad, mad. Uh we all we add all three these three
25:06:03
words. Now first of all we search using pad. So pad is not present. So we return false. Then bad is present because we
25:06:10
have previously added it. Uh then we are also given a word which is dot a d. So
25:06:15
this dot can actually mean anything. Uh and if we see we already have a word
25:06:20
like bad and dad that both and even mad that all three of them they actually
25:06:26
match with the string. So we can return true in this case as well. And we are also given one more search criteria
25:06:32
where we are only given B dot dot which means for these two dots we can conclude any other word. And since we already
25:06:38
have a word bad added we can conclude these two to be similar and we need to return true in this case.
25:06:46
So before we start the solution first let's understand that what a try is. Uh well uh if you want to check the full
25:06:52
explanation you can check out my previous video over here. Uh now let's move back over here. So basically a try
25:06:58
is actually a form of a tree whereas any given tree uh it has a root node. Now
25:07:03
this root node can have many subsequent children and each children can have some children of their own. Uh and based on
25:07:09
that we actually use try to search, store and iterate over different strings. uh and for any given strings we
25:07:17
actually use it uh character by character to store distinct values inside this given try and based on the
25:07:24
based on per character we actually store it in a manner where it becomes pretty uh fast for us to find that whether any
25:07:31
particular parent node contains some character as one of its children or not and then we iterate in some particular
25:07:37
fashion uh in DFS fashion to find uh any words.
25:07:42
So suppose these four are the strings we are trying to add. So let's uh initialize our try data structure. So
25:07:48
first of all we are actually going to have a root variable. Now for this root variable we are going to store all of
25:07:53
these values one by one. So first let's store the value hello. As mentioned that for any given string we are actually
25:07:59
going to go character by character. Uh so first of all we are going to take the character h and we are going to see that
25:08:04
does this root node has a child that is actually starts with h. It does not. So we are actually going to create a new
25:08:10
node over here and this node starts with h. Now we are going to add all the values of subsequent characters because
25:08:17
they don't exist. So I'm going to add append e uh l o. And after adding all of
25:08:23
these values actually we are going to have an end variable that denotes that this word has actually ended over here.
25:08:30
So, so far if we iterate in this direction in this given try we can actually form the word hello and when we
25:08:37
reach to this O we can actually we will actually encounter a special node that denotes that this is actually the end
25:08:42
node and if that whenever we identify that we can conclude the word has actually ended. Now let's add this word
25:08:49
high. So if we want to add word high basically first of all we will check that whether this h exists or not. So h
25:08:55
already exists as one of the children of this root. So we do not need to create a separate branch for this one. But the
25:09:01
thing is for this particular H I does not exist as one of its children. So we are actually going to create a new
25:09:06
branch over here I and we are going to denote that this is this represents this word H. And then because this word ends
25:09:14
over here we are actually going to denote an end node over here. Uh let's add one more word uh that is pop. So if
25:09:20
we want to add pop again P does not exist. So we are going to add or we are going to create a new branch and we are
25:09:26
going to add all of these values and we are going to add the end node. Now this next word is pawn. So again we are going
25:09:31
to use the same methodology. So P and O exist as the children. So first two characters we are done with. Now from
25:09:38
here we will have to create a new branch. So we will do that and after that we will add our end branch. And
25:09:44
this is the logic we are going to use to implement our uh insert or add method to
25:09:51
add different strings inside our word implement data structure. And this is the logic we are going to use that first
25:09:57
of all we are going to check that any character exist as the children of the root or not. If it exist we are going to
25:10:02
leverage that particular branch. If it does not exist we are going to create a new branch and then we will keep on
25:10:08
making separations and based on that uh things becomes pretty easy for us to find different words.
25:10:18
Okay. So for our search method suppose this is the try that we have actually created and these are the words we have
25:10:23
added. Uh let me quickly go over them. So first word is pen. If you look at this direction we have the word pen.
25:10:29
Then we have the pot. So P is common. So then there is a branch out and we get the word pot as well. Same we have cat,
25:10:34
cars and bed in the similar sequence. And uh these are the words we are trying to search. So couple of words are just
25:10:41
regular words. uh then I have added some examples with the dots in it. So because they are more complicated ones so we can
25:10:48
understand that. So let's start let's quickly start to go over and uh see that what would be our search policy for this
25:10:54
given uh try that we have created. So for for this character pot first letter
25:10:59
is P. So from this root we are going to see that does there a children that contains the character P and yes we have
25:11:05
a child that contains the character P. So based on that we will keep keep on iterating in that direction. So next
25:11:11
character is O. So we have O as well and the next character is T. So we have T as well. Now we don't care about this end
25:11:17
node because as long as we are able to generate the word that we were given we are good up until this point. So over
25:11:23
here we will actually return true to be the answer that yes this word is present inside the try that we have created. Uh
25:11:29
second word is pots. So again for the pots we up until this pot we are going to go in the same direction but this s
25:11:35
is not present as one of the children of this pot. Uh and because we encounter an end node over here. So we can uh drop
25:11:42
out immediately and we can return false in this case that yeah we don't have any uh character that matches the word pots.
25:11:49
Now this is little bit interesting example. So for this ar the policy we
25:11:55
are going to use is that whenever we encounter a dot to be a character we will actually have to iterate over every
25:12:01
single possible root using this dot to be the character and see that can we make this a r to be part of that
25:12:08
sequence or not. So let's uh quickly do that and let me clean this up a bit. For this dot a r the strategy we are going
25:12:15
to use is for this particular dot we are going to consider it uh that every single child of this root can be used
25:12:22
over here and then we will try to see that whether uh is there any place where second character is actually a. So first
25:12:27
we go down this path. Okay. So P we consider P as dot right. Then we check that okay this is E and this is not A.
25:12:34
So we cannot go on this path. Okay. Now we backtrack. Now we keep this P to be dot. Now again we try to repeat the same
25:12:40
process. This is A and this is O. So again this is not the path we are going to choose. This that is going to lead us to this answer. Uh we come back. Now
25:12:48
okay we are at this position again we check this child. So this child is actually C. We consider C to be the dot.
25:12:54
Okay. Now from the C the next character is actually A and all over here the next character is also A. So that is good
25:13:01
good sign for us. So now we can continue in that direction. So now from this a we will try to see that is there a child
25:13:07
that is actually r and yes from this a we also have a child that is r and since
25:13:12
we reach to the end of this word we can return true in this case that yes this dot a r is present inside this try that
25:13:19
we created okay so yeah that's a wonderful news uh now let's focus on the next example so next example is dot dot
25:13:26
t so for the dot dot t actually we are we will have to branch out even more so for the second dot dot t what we are
25:13:33
going to do Again we are going to repeat the same strategy. We will have to go over every single child that is
25:13:38
possible. So first we will consider this P to be the first dot. Uh so this dot is this P. Okay. Now from this P we will
25:13:45
also consider two child to be separate dots. So for both the childs uh okay
25:13:50
this is going to be the first dot. Uh so we are good up until this point. But this value is actually not T. This is N.
25:13:56
So we will have to backtrack from this E. We do not have any child. So we will again backtrack and we will come back to
25:14:02
this P to be one dot. Now from this P we still have one more root that we haven't considered. So we will consider this O
25:14:07
to be the second dot and from this O we actually have the last character T present and uh that matches the string
25:14:15
dot dot T. So if we go down this path uh we will be able to generate this word
25:14:21
and uh that's why we will also return true in this case as well. And the same thing we are going to repeat for this ey
25:14:28
uh strategy. So for this do ey we are going to do is first of all we are going to consider this to be the dot we will
25:14:34
see okay this is e so that is good but we this is not y so again we cannot go down this path uh again this is dot this
25:14:42
is not the path this is not the path this is not the path so this ey is actually not present inside this entire
25:14:49
try block that we have created so over here we will return false but before returning false we will actually try
25:14:55
check every single possible route to see that whether we can find a match or not. Okay, so that is how we are actually
25:15:01
going to implement the search mechanism. Uh basically the only tricky part is to take care of the dot values. Apart from
25:15:07
that, it's pretty simple. Now let's talk about time and space complexity. So for the add function, the time complexity is
25:15:12
actually going to be big of n that depending on the number of characters that are presented inside the input and
25:15:17
also for the space complexity, it's also going to be big of n depending on the size of the input. For the search
25:15:24
mechanism, things become a little bit tricky. Over here the time complexity is actually going to be big go of 26 * n.
25:15:30
Why 26 * n? Because remember for any given dot there can be 26 child of any
25:15:36
particular root element that we might have to iterate over. And again in the bottom we might have to keep on
25:15:41
repeating the same process. Right? So basically the maximum time and space complexity we might have to go over is
25:15:47
going to be uh n * 26. But since 26 is a finite number we can also consider this
25:15:53
to be big of n only. Okay. And for the space complexity, it's also going to be the same. It's going to be big of 26 to
25:16:00
the power of n.
25:16:06
So for this problem, we are being asked to implement three things. Word dictionary, add word and search method.
25:16:11
The thing is before that we will actually have to define a try node. So I'm going to create a separate class for
25:16:16
to defining a try node where every single try node has a different set of children and we can easily quickly look
25:16:24
up those children because we are actually using hashmap to define them. Okay. Now from our main method first of
25:16:30
all we are going to create a new try node. So now to implement our word dictionary first of all we are actually
25:16:35
going to create an instance of this try. Now for this add word method first of all we'll have to create a node. Uh so
25:16:42
we are going to create a try node. Uh we are going to run a for loop across the given word. If the current node if that
25:16:51
does not contain any children with this character then we will have to create a new entry inside our node
25:16:59
and if the entry exist for this given uh character uh we are actually going to go
25:17:06
to the next element and in the end we are going to define node.word to be true. So before we start our search
25:17:12
method, we are actually going to create a helper method called search in node. Uh that is going to take uh the input
25:17:19
word and the try node as the input and that is going to help us to iterate over the given try node. Uh so first of all
25:17:25
we are going to create a for loop to iterate over this given word and inside this given word we are going to iterate
25:17:30
over character by character. So I'm also going to create a new character variable. So first of all we are going
25:17:36
to check that if the given node or does its children contains this word or not. If it does not contain then we are going
25:17:43
to check that whether the given character is dot or not. And if that is the dot then we might have to iterate
25:17:49
over all the subsequent characters of this node. Once we determine that the children does
25:17:55
not contain this character ch we are going to check that whether the ch is actually a dot or not. If that is dot
25:18:01
then we are going to run a for loop across all the children for every single uh character value. And then we are
25:18:08
going to define a new try node called child. And basically we are going to call this search in node method
25:18:15
iteratively for the next character in that particular word because remember we
25:18:21
are already eliminating the dot character and uh providing its child as the try node and we will keep on
25:18:27
repeating this the uh we will keep on iterating this process and we are going to return true. If that is not the case
25:18:34
and if this given ch character is not a dot then uh in that case we can return
25:18:39
false immediately. uh somehow uh this ch is actually a
25:18:45
child of this node. If that is the case then uh we simply need to iterate over
25:18:51
the next value inside this given node. And in the end we simply need to return
25:18:57
that whether the node doword is present or not
25:19:02
and remember we are storing this node.word value inside our uh this add
25:19:07
word method as well. So the moment we identify matching word it would return true otherwise it would return false.
25:19:14
Now from this our search method all we will have to do is we simply need to call the uh recursive search in node
25:19:21
method that we have created and as the input we are going to provide the value of the word and we are also going to
25:19:28
initialize a new try node or we are also going to provide the try node that we initialized earlier and that's it. Uh
25:19:34
let's try to run this code. Okay, seems like our solution is working as expected. Let's submit this code.
25:19:42
Okay, seems like our solution worked as expected. Um, it was not the fastest solution in terms of time complexity,
25:19:49
but in terms of space complexity, it was pretty efficient. I would be posting this in the comments, so you can check
25:19:54
it out from there. Thank you.
25:20:07
Graphs are one of the most popular data structures that I personally struggled a lot with. So today I have decided to
25:20:13
create an entire course on graphs. We will understand that what graphs are, when to use it, what are the different
25:20:18
types, their applications, how to store them and we will learn 22 most asked,
25:20:24
most popular and most like lead code problems that has literally been asked at hundreds of companies thousands of
25:20:30
times. So without any delay, let's get started with this course.
25:20:38
Graphs are one of the most powerful tools we have in computing and also in real life to establish connections and
25:20:45
define many of the relationships. We all have studied graphs in our schools and in our past careers. But now let's try
25:20:52
to understand that what the graph is from the point of view of data structure and algorithms. So the idea is quite
25:20:59
straightforward. Typically a graph is defined by connection between more than
25:21:04
one parties and these parties are connected with each other in some sort of fashion and this is an example of a
25:21:11
graph that I just created. Now we can notice that graph contains two entities. There are these circular entities and
25:21:18
there are these uh lines that are connecting them and this is actually defined by nodes. So these circular
25:21:26
entities are nodes and they can also sometimes called vertices. So we can use vice versa and the connection between
25:21:32
these are defined as the edges. That's it. If you master nodes and edges, you
25:21:38
basically master graph. But it's not as simple as it seems. Now let's say that I
25:21:43
want to show you some practical examples of what a graph is in a real life scenario. Let's say that I want to
25:21:49
explain that how does my Facebook or Instagram looks like in a picture or in a diagram. So how would I represent it?
25:21:56
Well, one way to represent it is that this I can define it as my profile. So my name is part. So I'm defining it as
25:22:03
P. And let's just say that I current I am currently friends with five different people on Facebook. So I can define
25:22:09
these five people as dots and their own. And these edges define that we I am
25:22:15
currently friends with them and they are also currently friends with me. So that's why there are no arrows pointing towards each other. Now these friends
25:22:22
can have their own friends and it could be possible that I might have some mutual friends who are also friends with
25:22:28
each other. So this creates a whole big new social network where everyone is
25:22:34
connected with everyone and many people are not connected with everyone. Now in this example let's say that I want to
25:22:39
build a recommendation system that I want to recommend new friends for myself because I currently only have five
25:22:45
friends. So one logical way I can go about is that whoever are my friends or
25:22:51
like immediate friends of my friends could also be potentially possible that
25:22:56
they might be my friends as well. So I can start recommending these people to my profile who are not my friends but
25:23:02
friends of my friends but I would not recommend people like this who are friends of friends of friends of my
25:23:08
friend. So that would be like one degree advance and this is just one practical application. Now think the companies
25:23:15
like Facebook, Twitter, Tik Tok, they all completely run on the concepts that
25:23:20
are currently generated by graphs. So that's why they are so significantly important. Now when we talk about
25:23:26
graphs, there are actually four different basic types that we can talk about. First one are the trees. And yes,
25:23:33
trees are a different data structure on its own. But the thing is they are also a type of graph. The only difference
25:23:39
between a graph and a tree is that trees are connected which means every single
25:23:45
value or every single node inside a tree is connected and they do not have any cycles. That's the only difference. Next
25:23:52
type of graph that we can think about is that is typically a directed graph. So
25:23:58
what does a directed graph means? Now let's try to understand this with an example of Twitter. There is a very
25:24:03
famous profile for Eminem. Now Eminem has millions of followers. He has lot of
25:24:10
people following him. But Eminem does not follow anyone. So if we see if we if
25:24:15
I have to represent the graph of Eminem, I can define that currently Eminem. Let's say I want to define whoever is
25:24:22
following Eminem uh I just mark their profile arrows pointing towards Eminem
25:24:27
M&M. So this defines that all of these people are currently following Eminem.
25:24:32
But Eminem does not follow anyone. So there would not be any arrow pointing out where Eminem is following someone.
25:24:39
So this is one way to define relationship where one party is connected with the other party but other
25:24:45
party is not connected with the other party. Next is undirected. Now same way
25:24:50
we can see the example of Facebook where if I am friends with A where A is friends with B then B is also friends
25:24:57
with A. So in this case we can say that there are actually two directed edges that are going or pointing towards each
25:25:04
other or if I have to just mention it simply I can just simply say that there are two nodes and they are just
25:25:09
connected with each other where there is no direction specified. Then there are two more distinctions of graph and for
25:25:15
that is connected graph and unconnected graph. So what does a connected graph
25:25:20
means? Well, as the name suggests, let's say that if there are uh all of these different nodes and we can define that
25:25:26
all of the nodes are connected with each other in some sort of edge, then we can define it as a connected connected
25:25:33
graph. But if we have a graph like this where there are only three nodes but this node is not connected with any
25:25:40
other node and it's in a separate island in its own still this is part of a graph. It can be possible on Facebook
25:25:46
that I have created a profile where I don't have any friends and no one is friends with me. So I am still a
25:25:53
profile. I'm still a node but I just don't have any edges and that is absolutely valid. Now when we talk about
25:26:00
traversing graph we mainly talk about two methods depth per search and breath
25:26:05
per search and which is typically defined by DFS and BFS. Now DFS simply
25:26:12
means that let's say I'm currently located at this particular node. So from this node I can see that I have edges
25:26:18
pointing towards these five different nodes which means from this node if I have to travel I can very easily
25:26:24
traverse to all of these five nodes and through these five nodes then I can traverse to subsequent nodes. Now if I
25:26:31
follow the depth first search methodology then uh the logic is going to be that I pick a neighbor and for
25:26:38
that neighbor I would keep on going subsequently down to its neighbor. Once again I would pick a neighbor and then
25:26:45
once again I would keep going down towards that path. Now let's say that I exhausted all the possibilities and I
25:26:51
reached out to this neighbor where it currently does not have any more neighbors that I can visit. In this case
25:26:57
I can do a backtracking operation. I can check that whether there is any other node whose neighbors I haven't visited.
25:27:04
In this case, once again this does not have any neighbors. So once again I would do a backtrack operation. Once
25:27:09
again this does not have any more neighbors. And once again I would do the backtrack operation to my root node from
25:27:14
where I started and repeat the same operation in the other direction as well and so on and so forth. So I'm going
25:27:21
down in a particular direction in depth first search manner. Second option to traverse is that instead of traversing
25:27:28
in depth, I can start traversing in breath. So what does that mean? Well,
25:27:34
for any particular node, I will visit all the nodes that are currently associated with that particular node or
25:27:40
all the neighbors and then I would start visiting subsequent neighbors. So let's say that once again I start to traverse
25:27:46
from this end and I want to traverse in a breath for search fashion. So first I would visit this node, then I would
25:27:53
visit this node. Now notice that this node has some children of its own but
25:27:58
I'm not going to visit those. I'm going to visit all the neighbors of this node first. After visiting that now I would
25:28:04
pick on this node and once again start visiting its neighbors. So let's say that this node and if let's say that
25:28:11
this node also had these two neighbors. So once again I would visit this node then I would visit this node and this
25:28:17
node and after visiting all of the children then I will start visiting the these nodes. So in one fashion you are
25:28:24
moving out in breath and in other fashion you are going in one particular direction in depth till you reach to the
25:28:30
uh end of the path and then you do the backtrack operation. So this is just couple of ways to understand or traverse
25:28:37
over the graph. Now one last thing and that is that if I have to define that
25:28:43
what are the different ways to represent a graph then there are actually couple of ways. First way is let's say that let
25:28:50
me just draw a quick graph. So one way is to define them using adj adjacency list. What adjacency list means is that
25:28:58
I typically use a hashmap like data structure where I say that uh uh all of
25:29:04
these nodes. So 1 2 3 4 and five all of these nodes I'm defining. And now for these nodes I can define in these values
25:29:12
that what are the neighboring nodes of that. So for one I can define the neighboring nodes are going to be two
25:29:17
and three. Now for two I can define the neighboring node to one because remember
25:29:22
this is an undirected edge. So which means one is neighbor of two and two is also neighbor of one. So once again for
25:29:29
two I only have one neighbor that is one. For three I only have one neighbor that is one. For four I only have one
25:29:35
neighbor that is uh one. And I did not define four over here but four over here as well. And for five I only have one
25:29:42
neighbor that is four. And this would be a representation of this graph in adjacency list manner where we have we
25:29:49
are clearly defining what the nodes are and what are all the different uh neighbors connected with each. And the
25:29:56
second way to represent the graph would be using adjacency matrix. And in the adjacy matrix we are simply defining all
25:30:03
the nodes that we currently have and then whenever we see an edge between them. So let's say that we currently
25:30:08
have an edge from 1 to 4 and 4 to 1. So from 1 to four we can mark as true or
25:30:13
one and same way for 4 to 1 we can mark it as true or one or and for all the other values we can define it as zero or
25:30:20
false something like this. So this would be two different ways that we are going to represent graph inside our computer
25:30:27
programming and both of them are very useful and very popular. Just a quick suggestion when to use which one. If you
25:30:34
are dealing with less edges then it would make sense to use adjacency list
25:30:39
because you are only dealing with small number of connections. But if you are dealing with lot of edges and lot of
25:30:45
dense graph then it would make sense to use adjacency matrix because remember over here the uh retrieval would be bigo
25:30:54
of one time because you can directly see that whether two nodes are edges of each other or not. In this case, in the worst
25:31:01
case scenario, this can be big of because notice that over here we are facing some contention. So that's why it
25:31:08
would make sense. But the thing is the time complexity for sorry space complexity for this one is big of n
25:31:14
square that is more expensive and uh for adjacency list it it is much less
25:31:19
expensive. So I explained I gave you a brief intro. Now let's try to learn the
25:31:25
22 most task most popular most like lead code problems and uh by the end of these
25:31:32
22 after completing these 22 questions you would be pro in all sorts of graph
25:31:38
questions that is my guarantee so without any delay let's get started so the question is number of provinces this
25:31:45
is a late code 547 problem and this problem has been popular amongst top tier companies so companies such Amazon,
25:31:53
Bloomberg, Apple, Two Sigma, Door Dash, Goldman Sex, Google, Uber, they have all
25:31:58
asked this problem. So that's why I hope that you pay enough attention to this one. If we see the problem statement, uh
25:32:06
problem statement defines that there are n cities that we are given and we are
25:32:11
told that some of these cities are connected, some of these cities are not connected. Now if uh say a city a is
25:32:21
connected with city b and city b is directly connected with city c then city
25:32:26
a is indirectly connected with city c. So a is connected with b is connected
25:32:32
with c. Suppose this is the relationship then we can define that a is also connected with c. This is what this
25:32:38
problem is uh the statement is referring to. Now going back we are given the
25:32:43
definition that what a province is. A province is a group of directly or indirectly connected cities and no other
25:32:52
cities outside of this group. So suppose we are given cities like A, B, C, D,
25:32:58
something like this. And we are given that A is connected with B, B is connected with C and we are also we can
25:33:05
also refer that indirectly A is connected with C as well. Currently this B is not connected with anyone. In this
25:33:12
case we can define that this A B C makes a province and this D by itself
25:33:18
currently since it is not connected it is not making a province. But suppose we
25:33:24
identify that another city E that exists that is current connected with city D
25:33:29
then we can define this to be the second province as well. Okay. So now we are we
25:33:35
know that what the problem statement has given us. We are given n cities and we are given the de the connection between
25:33:42
those cities and we are also given the definition of what a province is. Now we are given an n cross n matrix uh and
25:33:51
wherever there is a connection between any two entities we are that particular value has been marked as one that
25:33:58
defines that the i city and j city is connected and uh if the value is not one
25:34:03
if the value is zero which means that those those values are not connected. Now based on this given input we need to
25:34:11
define the total number of provinces. This problem is very similar to one of the previous problems we solved and that
25:34:17
is the number of connected components and how let me just quickly show it to you. What we are given is that we are
25:34:24
told that we are given a matrix and inside the matrix uh using by using the
25:34:31
values 0 and 1 we are going to define that whether any two values are connected or not. Okay. So suppose the
25:34:37
values are a b c d and here a b c d. Okay. All the values are by default
25:34:44
going to be connected with each other. So I'm going to mark it as one. Suppose let's just take the same example. So
25:34:50
these are all the items we are given. This is true. Based on all of these
25:34:56
items, what we are given is that this is actually not a matrix but actually this
25:35:02
is an adjacency matrix and adjacency matrix is one more way to represent a
25:35:08
graph. Since this is one more way to represent a graph, we can rather than considering
25:35:14
these as cities and these are connection between them. Let's just try to think of
25:35:20
these as nodes and edges where nodes are the cities and edges are the connection
25:35:26
between them. And now this becomes a very simple problem that we can solve using BFS quite easily. And the whole
25:35:33
problem statement now becomes is that we need to identify that how many number of connected component exist inside any
25:35:41
given graph. And uh those connected components we need to return them as the answer. So I have already solved this
25:35:47
one in past but I'm going to quickly show you the solution again. And simply we are going to use breath first search.
25:35:54
For breath first search we all know we need two items. First one we need is a Q and we need some way to keep track of
25:36:00
all the visited nodes so far. So let's just do that. I'm going to initialize
25:36:06
our Q and also I'm going to initialize our hash set that is going to keep track of the visited hashet. Okay. So this one
25:36:12
is for visited and this one is Q. Now we can start at any given node. So suppose this is the input we are given.
25:36:19
Currently nodes are 1 2 3. These three cities are connected and city four and five is connected. We are also going to
25:36:25
mark one more variable called provinces. And initially the value of the provinces is going to be zero. Okay. So currently
25:36:32
this is the variable that is going to keep track of the number of provinces we have been able to find so far. Currently
25:36:38
the value is zero. Now let's just pick any arbitrary value. So we start with node one. So let's just do uh let's just
25:36:45
run a bfs starting with node number one. So first we are going to since one has
25:36:51
not been visited we are going to mark as visited because we are visiting it. We are going to add one inside our que. Now
25:36:57
the moment we find a value inside a queue, we are going to iterate through its neighbors. Currently one has two
25:37:02
neighbors, value two and value three. Both value two and value three are not visited. So we are going to mark them to
25:37:09
the number of visited nodes and we are going to mark two and three here. Now we iterated over all the neighbors of one.
25:37:15
So we are going to dq one out and uh we are going to remove it from the que. Now currently we only have values two and
25:37:22
three. For value two the number of node is 1 and three as its neighbor. Both one
25:37:27
and three have been visited. So since they are visited, we are not going to revisit them and we are going to pop two
25:37:33
out as well. That stating that we visited all the nodes of two and at the same time we are going to pop three out
25:37:39
as well since uh the neighbors of three 1 and two are already been visited. Also
25:37:45
I forgot one key important thing. uh and that is that the moment initially when
25:37:50
we started iterating through one and we found that one has a neighbor two immediately we needed to add the number
25:37:58
of provinces to one because we found at least one province. So uh we would have
25:38:03
found one province and in order to finding that province we already visited all three nodes. So we are going to mark
25:38:09
these three nodes as as visited. Now since in the input we are already given n is equal to 5. We initially started
25:38:16
with n is equal to value number one because it was not visited. Now we will start with n is equal to 2 but that has
25:38:22
also been visited. So we will simply skip over. n is equal to 3 has also been visited. So we will simply skip over.
25:38:28
Last value is n is equal to 4. n is equal to 4 has not been visited. So
25:38:33
marking four to our visited list. Adding four to our que. And now four has a
25:38:38
neighbor five. So again the moment we find a neighbor we are going to increase the number of provinces to two. We are
25:38:45
going to add five to our visited list. We are going to five add five to our que and then we are going to pop four out
25:38:52
because we visited all the neighbors of four. But we haven't visited all the neighbors of five. Currently for five
25:38:58
since five has already been visited, we do not care. But five's neighbor four has also been visited. Which means five
25:39:05
we also visited all the neighbors of five. So now we get rid of five. Now initially for this n is equal to 5 we we
25:39:12
had gone through 1 to four. For the fifth value five is is also present inside the number of visited list. So we
25:39:19
can define that five has also been visited and because of that we went through all the nodes or all the cities
25:39:26
that we are we were given and the number of provinces that we were able to make was two and which we are going to return
25:39:33
as the answer. If we see solution for the time and space solution for this one, basically the time complexity is
25:39:40
going to be bigo of v + e where v is the number of vertices or number of cities
25:39:45
in this case and e is the number of edges or the connection between the cities uh that we are given pretty
25:39:53
simple and this is uh pretty standard space complexity also going to be bigo
25:39:58
of v because the space complexity is based on the visited hashet and the q that we have to generate which can hold
25:40:05
maximum up to five cities for this example. So it is directly related to the number of vertices that is present
25:40:12
inside our given example. Awesome. So see how knowing BFS made our life so
25:40:18
much easier. Let's move on to the coding explanation for this problem. Let's see the coding solution for the number of
25:40:24
provinces problem. This is a really unique problem and the solution is actually quite simple. First of all, in
25:40:30
the main method, we are given the 2x2 matrix that defines that what are the number of connected components. Based on
25:40:37
that, we would be able to easily identify that what is the total number of edges or total number of nodes
25:40:43
present and uh once having that we are going to initialize our visited boolean
25:40:48
array and initially the number of provinces is going to be zero. Now the
25:40:53
uh we are going to run our for loop where we are going to call the BFS method. Inside the BFS method, first of
25:40:59
all, we are going to check that whether the current node has been visited or not. If the node has not been visited,
25:41:05
we are going to call BFS method to visit all the connected components or all the cities that are connected with each
25:41:11
other that form a province. And we are going to increase the number of provinces. So we are going to do
25:41:17
provinces plus that was initially loc set set it up as zero. Now let's see that what is going to happen inside our
25:41:23
BFS helper method. The answer is quite simple. uh in the BFS we are going to
25:41:28
initialize our queue and we are going to have a visited array that to keep track of all the nodes that we have visited so
25:41:35
far. For any single input that we are given, we are going to keep on iterating
25:41:41
all the neighbors of that particular node that it is currently connected to
25:41:46
and we are going to mark all of them visited. So even when we encounter the same city that that has already been
25:41:52
processed, we do not reprocess it again because it has already been marked visited. And after this entire process
25:41:59
ends currently in this loop, this provinces variable should have all the answers populated. We can simply add
25:42:06
them over here and return provinces as the answer. So let's try to run this code. Seems like our solution is working
25:42:12
as expected. Let's submit this code. And our code runs 99.26%
25:42:18
faster. So this is pretty fast solution and don't worry about this. I'm going to paste this solution inside my GitHub and
25:42:25
the link is in the description so you can check it out from there.
25:42:35
Hello friends, the problem we are going to do today is one of the most versatile most asked question in the history of uh
25:42:42
lead code questions. Like if you just look at the sheer numbers of the amount
25:42:47
this question has been asked and the range of companies this question has been asked it like it's just
25:42:53
mindboggling. Uh whatever your dream company might be in the entire world this and if they do good technical
25:43:00
interviews they must have asked this question probably at least 2 3 5 10 times uh to their candidates. If I only
25:43:06
had 10 minutes to prepare for a technical interview I'm going to choose this question at at the top of my
25:43:12
choice. Like just look at the the the companies over here like Amazon, Microsoft, Bloomberg, Facebook, Google,
25:43:18
LinkedIn, Oracle, Apple, Bite Dance, which which is basically Tik Tok, Door
25:43:24
Dash, Yahoo, PTM, uh Walmart,
25:43:29
Tesla, Samsung. So I doubt that there are any companies left that didn't ask
25:43:37
this question. And the question we are going to do today is number of islands. And uh I'm going to pay my utmost
25:43:43
attention to this problem. Now in the input problem, we are given a
25:43:49
grid of m cross n as a 2D binary matrix. And uh in this particular grid, we are
25:43:56
uh the all the cells are filled with either values of one or value of zero. And whatever the value that represents
25:44:03
as value of one actually represents land in the real life. And all the values that are marked as zero is actually
25:44:11
water. And we need to find that what are the total number of islands inside this
25:44:16
particular grid. Now based on the definition we know that suppose if we have uh some sort of body of uh land
25:44:25
something like this and if it is entirely covered by body of water we can
25:44:31
say that this particular body of uh land is actually an island and uh we that is
25:44:38
what we are trying to find in this given problem. Now we are also told one more
25:44:44
thing that at the edges of this particular grid like all of these values
25:44:50
this is also water. Which means that suppose we are given uh an input like
25:44:56
this where uh all of these values are zeros
25:45:03
and we only have just one single one over here. This we can also conclude as
25:45:09
an island because uh on these three sides of the island is already water and
25:45:17
on the outside is also water because we are told that everything on the outside
25:45:23
is also water. So just keep keep this in mind that if we find some place at the
25:45:28
edge of the grid we still consider it to be surrounded by water. If all the other
25:45:34
side inside the grid is also water and our aim is to find that uh how
25:45:41
how what is the maximum number of islands that are present inside the given grid. Now this problem is actually
25:45:49
pretty simple like if you if we just see over here like in this particular input if we try to find for this example one
25:45:56
that how many number of islands there exist actually there only exists just one island and that is uh this one
25:46:04
because notice this that these all ones are actually able to be connect with
25:46:09
each other because they're adjacent to each other. Uh if for any particular cell uh suppose this is marked as one
25:46:16
and this is a part of land and uh any cell adjacent to this cell is also
25:46:22
marked as one. We can say that both of these are a common part of land because
25:46:27
there does not exist anything in between. They are right adjacent to each other and this is what we are given over
25:46:33
here. So in this example we only we can only find one island. Now if we take the
25:46:39
second example, we can see that there are actually more than one islands. So this is the first island that we can
25:46:46
find. This one is by itself. Uh and if we see all four sides of it, uh this is
25:46:52
zero, this is zero, this is zero and this is zero. So this is also an island. And these two ones, they are also an
25:46:58
island. So in this example, we actually have three uh three distinct islands.
25:47:04
Okay. Suppose we are given a custom example like this and I have mentioned in my previous videos that it it is
25:47:11
really important to come up with your own custom examples because it shows that you can think on your own and you
25:47:16
can create test cases on your own. It's a really important skill for any computer engineer to have. Now suppose
25:47:23
this is the grid that we are given and uh this blue line indicates the body of
25:47:28
water we have outside of our original grid. So this is just for uh understanding purposes. I'm just going
25:47:34
to get rid of it now so it does not uh become an issue and I can explain the
25:47:39
problem better. So we know that there is water outside. Now the most basic
25:47:45
approach is that we start traversing through the entire grid in some manner
25:47:52
like there are bunch of different ways to traverse through the the given grid and we try to see that at any moment if
25:47:59
we find one which means that so far we have find a body of water uh land. Now
25:48:06
since we have found this one, we need to see that what are the different islands we can create and we can create bunch of
25:48:14
different islands. If uh all the values are relate are connected with one like
25:48:21
no matter how many number of values are connected with any single one we would mark all of them as just one island as
25:48:28
long as they they are connected with each other. And basically what we are doing is we are trying to find separate
25:48:35
set of ones. Understand what I'm saying? We are I I will repeat we are trying to find
25:48:41
separate set of ones. So in this example if we just see that how many different
25:48:46
sets we can find like we can find this one set of one
25:48:52
we can find this another set of ones and we can find this third set of ones. And
25:48:59
over here we only have one individual element but still that is a set on its own like even if we only have just one
25:49:06
acre of land it's still a piece of land which we can consider as island. So that
25:49:12
is what we are trying to find and uh let me just revert back. Okay. So now we
25:49:18
know that what we are trying to find the most basic approach is we start
25:49:24
traversing through the given input array and uh we start traversing okay suppose
25:49:31
we traverse the first row we don't find anything okay now again we starts
25:49:36
traversing over here we don't find anything now at this point we find that okay there exist an element one over
25:49:43
here the moment we find that there exist an element one over Here we are going to
25:49:48
call our function and basically what that function is going to do is it is
25:49:53
going to iterate over all the adjacent cells and it is going to keep on iterating till we exhaust all the ones
25:50:02
that are connected with this one. So till we exhaust all the sets that are
25:50:08
associated with this particular one. So let me just go back a bit and uh this
25:50:15
is the approach we are going to take that initially currently we came to this particular item we find that okay there
25:50:22
exist a one over here now that because there exist a one we need to find all the ones that are connected with this
25:50:28
one. So what we are going to do is we are going to mark this coordinate and once we have this coordinate location
25:50:35
first of all we are going to uh increase in the number of islands we have like
25:50:40
initially we the number of islands we have is zero. Now we because we find at
25:50:46
least a single one which means that we have found at least one island. So we will update the the number of islands we
25:50:53
have. Now since we have already updated the number of islands uh and we have we
25:50:58
already have coordinates for this one. First of all we will mark this one as zero. So let's mark this one as zero.
25:51:06
Okay. And now from this coordinate we will try to find all of its neighbors to
25:51:11
see that there exist any adjacent ones. So over here we find that uh okay this
25:51:18
one is also one and this one is also one. So we are going to repeat the same process. Uh and remember we are not
25:51:24
going to update our islands in this case because we are still connected with whatever the previous value we had found
25:51:30
before. So we are still in the same set of one that we were dealing with. So
25:51:35
there is no point in updating that but we have to exhaust all the ones that are connected with this original one we had
25:51:41
found before. So we will check over here. Okay, this is one. So because this
25:51:47
is one we will uh come we will change its value to zero because it it now it
25:51:54
becomes part of this uh original set we had. Uh now again we are from here we
25:52:00
are going to repeat the same process. Okay we don't find any once from this point. So we are good. But remember over
25:52:06
here we we didn't ex exhaust all the possibilities from our original coordinate. So we still have to do some
25:52:13
work. So again we will come back. we will find one over here which means we will have to turn it turn it to zero. So
25:52:20
we will convert this one to zero as well. And now from this particular uh position we will try to repeat the same
25:52:26
process. So we will check all of its neighbors and all of it neighbor its neighbors in this scenario are now zero
25:52:33
which means we are good like we have at least exhausted some possibility and we
25:52:38
are and we have at least found one set of island. Okay. Now we will again
25:52:44
repeat with our process and notice that I convert all these
25:52:50
three values to zeros because we already found an island over here. And now uh we
25:52:56
will repeat the same process. So again we will start traversing our uh matrix and over here we encounter the one again
25:53:03
which means now we have encountered a new set of island. So we will update the value in our islands. We will update
25:53:10
this to two. Again we are going to repeat the same process. So first of all we will update uh this one to zero.
25:53:18
And uh now this is zero. We still have to check its neighbors. We find an adjacent neighbor. Again we uh we flip
25:53:26
it to zero first. And again we go to the next element. Again we flip it to zero.
25:53:32
And now we won't find any more neighbors that uh are uh basically one. Which
25:53:38
means that again we will start traversing. So we keep on traversing over and over and over and we don't find
25:53:44
any ones. But now we are at this point. Again we find the one we update our
25:53:49
island. So our number of island becomes three. And now we need to find all the
25:53:54
neighbors that are present in this particular island and we set all of the
25:54:00
those values to zero. So these values are set up to zero. And now we check
25:54:07
that okay no neighbor actually has a value of one which means we have exhausted all the possibilities of uh
25:54:13
number of neighbors uh that could be a part of the island and now again we repeat the same process and now we find
25:54:19
this one and this is the last element. So again we increase the number of islands that we have found to four and
25:54:26
we set this up to zero. And now because we have exhausted all the possibility
25:54:32
and we reach to the end of the grid we can simply return whatever the value we find in the number of islands and that
25:54:38
would be our solution. Suppose we we were given uh an input with all the zeros like over here we wouldn't have
25:54:43
found any island and we we can simply return zero in that case as well. But this is like a very basic approach and
25:54:50
the approach we took in this scenario is actually depth first search uh to find
25:54:56
the set of ones that are adjacent to each other. Like we could have used the
25:55:01
BFS as well but I mentioned earlier like I'm trying to learn graph theory and first I'm going to master DFS then I
25:55:09
will start working on the BFS. So that's why I decided to do choose the approach
25:55:14
of depth first search in this scenario. Okay. And uh the time complexity in this case would be actually big of m cross n
25:55:24
time complexity because that is in uh we have to iterate over entire grid that is
25:55:29
given and the space complexity would also be bigo of m cross n in the worst
25:55:34
case scenario. Suppose that we are given a grid where all the values are just ones which means that for every any
25:55:41
single element we'll have to iterate over all the the entire uh grid and uh that could be the worst time worst time
25:55:48
and space complexity.
25:55:55
First we'll create two parameters row and column to calculate the uh current row row and column values for the given
25:56:01
grid. Okay. And we will also create a variable
25:56:07
called island. And initially we will set it up to value zero. And we would update
25:56:12
this every time we encounter one inside the given matrix.
25:56:19
And inside the loop we will have a condition that if the current i and j
25:56:25
position inside the grid is actually equal to one.
25:56:33
then only we are going to call our DFS function. So first we'll do island uh
25:56:38
we'll increase the value of islands
25:56:44
and now we will call our DFS function. In the DFS we are going to provide the e
25:56:51
to position the j position and we'll also provide the grid
25:56:56
that uh we are working on. And uh once this loop ends like we should have all
25:57:02
the set of separate ones and uh we should have all the values of the total
25:57:08
number of islands. So we can simply return the number of islands we have found.
25:57:15
Okay. Now we need to create the logic to implement this DFS function. So first
25:57:21
we'll create a function. Inside the function we will need the
25:57:26
values for uh the row and column again for the entire grid. So we'll just name them new row and uh this would be
25:57:36
grids length and we will also create a parameter called new column. This would
25:57:41
be the first uh positions length.
25:57:50
And uh this is basically the same as finding the row and column we found over here. But we need to use it. So I'm just
25:57:56
giving different names. We'll also create a 2D array of uh
25:58:04
called directions. This would make our lives easier and allow us to iterate over uh all the
25:58:11
adjacent values of any current position. And we are going to initialize it with
25:58:18
default values. We have this established. First we will
25:58:24
put a condition that if the current row and column are they out of bounds or not.
25:58:32
We will also put an additional condition that if uh the current value we are at
25:58:39
inside the grid if that is already zero or not.
25:58:45
because if that is already zero, we won't have to do anything. So if any of the these conditions satisfy, we can
25:58:52
simply break out of the DFS function. And this would be our terminating case.
25:58:59
If this is not true, first of all, we will uh update the current position we
25:59:04
are at inside the grid and we will name we'll enter the value
25:59:12
as zero because remember we have already updated the uh island islands and now we
25:59:18
will just run a for loop and iterate over all the four
25:59:25
directions. So that will be that will allow us to go over all the neighboring
25:59:31
uh candidates of this row and column uh that we have.
25:59:40
And now we are simply going to call DFS on uh row plus
25:59:47
direction of zero and column plus direction of 1.
25:59:56
And we'll also provide the value of grid as well. And uh yeah, I guess this should be our
26:00:04
logic. And uh we can try to run this code.
26:00:12
Okay, looks like we messed something up. Oh,
26:00:17
okay. Seems like our solution is working. Let's try to submit the code.
26:00:24
Seems like our solution is also working but it's not the most efficient solution and uh I'll try to make my solution
26:00:31
better because maybe there is some other way we can solve this problem and uh if I find out I'll probably make a video on
26:00:38
that sometime in the future. Meanwhile, let me know in the comments if you have any thoughts regarding this problem.
26:00:53
So the lead code problem we are going to solve now is called maximum area of islands and we can see that this one is
26:00:58
a medium problem and also a very well-like problem. The statement is quite straightforward. We are given an M
26:01:04
crossN binary matrix named grid. Now for this particular grid we are given bunch
26:01:09
of different ones and bunch of different zeros. Now we are being told that once represents an island and zero represents
26:01:17
just water. Okay. Then we need to return the maximum area of an island that we
26:01:22
can make inside the grid. And if there are no islands that we can form, we need to return zero. Plus we are being told
26:01:29
that every single cell with value one is uh the island. And if there are bunch of
26:01:34
different ones connected with each other, then we need to basically do the addition of all of those cells and then
26:01:40
we can consider them as one entire block of an island. So let's try to understand this with an example. Here is an M
26:01:46
crossN grid we are given and we can see that there are bunch of different zeros and bunch of different ones. Now some
26:01:52
ones are isolated. So this is just an island in its own and we can see that
26:01:57
the area of this particular island is going to be value number one because it is only connected with just one uh
26:02:04
island by itself. But if we take a look at some other islands, we can see that they actually form bunch of different
26:02:10
ones that are adjacent to each other amongst all four horizontal values and that increases the area of those
26:02:17
particular island. So we will have this island that is of size four. Same way this island of size five and so on and
26:02:23
so forth. Now we need to return the island that contains the maximum value.
26:02:29
So in this case this island chain or this connection of ones are actually
26:02:34
total area of six. So in this case we will need to return the maximum area of islands as six as the answer. So this is
26:02:43
what we need to return. Now let's try to understand that what are the different logic we can take to solve this problem.
26:02:50
Now uh we know it's a very straightforward problem. The idea is that we are going to iterate in one
26:02:56
single direction uh from the starting point and the moment we identify that there exist some island or value number
26:03:04
one then we need to iterate over every single possible neighbor of this
26:03:09
particular one. And the moment we exhaust all the possibilities by exploring every single neighbor we can
26:03:16
determine that that has been the current uh area that we have been able to find. Plus we will also need to keep track
26:03:23
that what is the maximum island V island chain we have been able to identify it so far. So let's try to understand the
26:03:29
most common basic approach to solve this problem. Let's say that we start iterating from this very first cell in
26:03:35
sequence in just regular sequence. So we say that this is water. This is water. So there is no area we can find. We come
26:03:42
to this node. This value is one. So the moment we identify one, we will have to take a look in all four directions to
26:03:49
see if there are any possible island chains that we can make. Since in this case there is there are no island chains
26:03:55
we can form. We can say that the area of the current value we have been able to identify so far is one. And so far we
26:04:02
have only found one island with area one. So the maximum area we found so far is also one. After doing this, we will
26:04:09
have to mark this one as being visited because we have already visited this node. And why are we marking it visited?
26:04:16
I'll just explain it to you later. So let's say that we mark this one as visited as well. Okay, that this this
26:04:22
one has already been taken care of. We iterate again. Nothing. We we don't find anything. Once again, we find one more
26:04:28
one over here. Which means we will have to uh do the iteration for our current updation right now. So once again, we
26:04:35
start looking in all four directions. The moment we go to this direction, we find one more one. So once again for
26:04:41
this particular one, we will have to repeat the same operation. Look in all four directions. And here the problem
26:04:47
may arise. Let's say that we look in this direction and this direction and then we decide to look up into this
26:04:52
direction. So this is also a neighbor of one. And we can also by mistakenly
26:04:58
calculate this one once again. So as part of the island which means we may
26:05:03
stay inside an infinite loop and that's why in order to prevent that issue the
26:05:08
moment any particular value that we have visited we are just going to mark that that value has been visited. So we don't
26:05:14
recount those values again. So let's say that we count this value then this value then we go into this direction and this
26:05:20
direction and so far we have visited all of these four ones and the current area so far we found is four which means
26:05:27
maximum area also needs to be updated. So we are going to update the maximum area once again. Now we start our
26:05:34
iteration in the similar fashion. These are all zeros. So nothing to do with this. Once again this one would have
26:05:40
been one but we since we already visited this one there is no point in redoing the same operation. So we are just going
26:05:47
to go and ignore this case completely and once again we are going to ignore
26:05:52
all of these cases. Once again we identified one one. So so far the area is going to be four. We cancel out all
26:05:59
of these four nodes as well. And we keep on repeating the same operation until we find the maximum area which we would
26:06:06
find when we get to this particular one as value number six. And this is what we need to return in this case. So the
26:06:13
moment I was explaining this solution, it should completely come to your head that this is actually a graph problem
26:06:19
where this given m cross n grid is actually the matrix we are given that
26:06:25
represents a graph. It's an adjacy matrix. And for this adjacy matrix all
26:06:31
we need to do is we will have to find that what are all the connected components for any particular graph and
26:06:38
the cluster of the connected components whichever has the highest value we simply need to return that as part of
26:06:44
the answer or as part of the area we have been able to calculate so far. Now we know with any particular graph
26:06:51
problem the most important thing is that how we are going to iterate over the graph. So we know that iterating over an
26:06:57
M crossN grid is quite straightforward. We simply need to run two for loops to iterate over that. The moment we
26:07:03
identify any particular one then we will have to explore in all four directions
26:07:08
and iterate over the entire set of directions where whichever the value is
26:07:13
one and we will have to keep on repeating the same operation. So logically all we are doing is a depth
26:07:19
first search whenever we identify any particular one that exists. We can also do a BFS but DFS in my opinion would
26:07:26
make much more sense in this case because we need to go in any particular direction. Uh it won't change the result
26:07:33
but I just like to use DFS for this particular type of case. Uh then in
26:07:38
order to complete the DFS and not run into the issue of uh recounting the same value we will have to keep track of and
26:07:45
all the visited nodes. For that we have two options. One option is that we can try to manipulate the existing input.
26:07:53
But let's say that your interviewer is very picky and he or she does not want you to play around with originally given
26:07:59
input. So instead of playing around with originally given input, you can also create a m cross n matrix and just mark
26:08:06
all the values by zero whichever the ones that you have visited so far. So that way also you can just keep track of
26:08:12
all the nodes that you have visited and you are only going to do a DFS on unvisited nodes. So that's it. That is
26:08:18
the whole solution. And on top of it, for the entire duration, you are going to keep track of the current area that
26:08:26
you have found so far and the maximum area that you have been able to find so far. And combination of this would
26:08:32
actually solve this problem quite simply quite easily. Let's try to understand the time and space complexity in this
26:08:38
case. Time complexity is simply going to be go of m cross n because we will have to iterate over every single cell. And
26:08:45
even for our DFS operation, we are going to mark those nodes as as visited. In terms of space complexity, because we
26:08:51
are using an extra space to store all the visited nodes, it is also going to be big of multiplied by n or nodes
26:08:57
multiplied by edges. So in this case, overall this is a very good time and space complexity. Once you understand
26:09:03
that this one is an is actually a graph problem, it becomes very simple to solve
26:09:08
and also move forward. So now let's quickly see the coding solution for this one. So the coding solution is quite
26:09:15
straightforward. Uh we are given our max area of island uh that we need to find
26:09:20
and we are given the grid as part of the input. First thing we are going to do is to check that if the given grid is equal
26:09:25
to null then we are simply going to return zero. It's an edge case. Then we are going to initialize a variable
26:09:31
called max area and initially the value is going to be zero. Then we are going to iterate over every single value that
26:09:38
is currently present inside our grid using two loops um i and j. And for
26:09:44
every single value first thing we are going to check is that if the given grid position if that is equal to one then we
26:09:52
will start calculating the area of this current one that we have been able to identify so far and we will have to
26:09:59
iterate over in all four directions and that's where we are using the dfs method. Next thing for every single one
26:10:06
that we have been able to identify so far, it could be possible that that particular value could be the maximum
26:10:12
area we have been able to identify so far. So we we are going to compare the maximum area we have so far and the new
26:10:19
area or the current area we just found for this particular D through this DFS call. Now let's understand this DFS call
26:10:26
and how does it work. In the input, we are providing the grid that we are working with. We are also providing the
26:10:32
current I and J position. Very first thing we are checking is that if the
26:10:37
given grid is going out of bounds in either one of these cases, we are simply
26:10:42
going to return zero. Or if the given grid position I and J that we are
26:10:47
working with, if that is also zero, then also we can return zero. If that is not the case, we are going to mark this cell
26:10:54
as visited. Now, in this case, I'm not using an extra hashet. I'm just uh using
26:10:59
the same grid to update the call. But if your interviewer asks you that you cannot change the given input, then you
26:11:06
might need to create a new instance of uh new M crossN matrix and repeat the
26:11:12
same operation. Then we are going to add value um of area by one. And then we are
26:11:19
going to make four different calls in all four directions. And we are going to
26:11:24
do the plus and equal to operation for the area. Which means for every single one that we are being able to identify
26:11:31
in each four each of these four areas, we are going to add that value to our existing area and we are simply
26:11:38
returning the area in the end. So this is this is our helper method where recursively we are using the DFS
26:11:43
operation and we are updating updating updating the area of the current area we have been able to identify it so far. In
26:11:50
the end we simply need to return the max area we have been able to identify so far once this for loop call ends. So now
26:11:57
let's try to run this code.
26:12:03
Okay, seems like our solution is working as expected. Let's submit this code.
26:12:10
And our code runs 100% faster than all the other solutions which is exceptionally good. So once again the
26:12:17
solution is present in our GitHub repository. So feel free to go ahead and check it out. Thank you.
26:12:30
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do number of connected
26:12:36
components in an undirected graph lead code problem. This is a graph theory problem as you can you can see from the
26:12:41
name and this problem has been asked in one of my favorite companies. Amazon, LinkedIn, Facebook, Pinterest,
26:12:47
Microsoft, Google, Bloomberg, Apple, Twitter. So these are all my dream companies. I want to get get a job at
26:12:54
any one of them and that's why I'm making these videos. So I would be paying my utmost attention. I hope you
26:12:59
enjoy the video. So this is a lead code medium problem. But in my opinion, this should have been
26:13:05
an easy problem. And if we look at the problem statement, we are given nodes of a graph and we are given a uh an array
26:13:12
of edges and those edges are undirected. Which means if we are given an uh edge like this that A to B uh which means we
26:13:20
can say that we can go from A to B and we can also come from B to A. Now we need to return that based on this given
26:13:27
input how many different of different kinds of connected component there exist
26:13:32
inside the given graph. So over here we are given an example with five nodes uh 0 1 2 3 and four. These are the five
26:13:39
vertices of of a graph and we are given some array of edges. Based on these arrays uh we are able to see that there
26:13:47
exist these this is the graph and there exist these two different set of connected components. So over here
26:13:53
because there are two connected components we need to return to. Suppose we could have given some example like
26:13:58
this that 0 1 2 3. Uh so this is one connected component inside the graph. Uh
26:14:05
then there is also one more node that is isolated and then there is one more node
26:14:10
that is something like five six something like this. So in this case how many different connected components we
26:14:16
can find. So if we see over here the number of different connected components we can find is 1 2 and three. So in this
26:14:23
case we would iterate over this given input and we would say that hey there exist three separate connected components
26:14:30
and let's see that what could be the intuition behind the solution for this one.
26:14:36
Okay suppose we are given a custom example like this and always remember that is it is really important to come
26:14:41
up with your own custom example uh in any interviews. So suppose we are given a custom example like this where the
26:14:47
number of nodes we are given is eight and these are list of edges that we are given. Now based on these edges we are
26:14:53
able to form a graph like this and we can imagine that there exists a graph like this. Now over here if we just look
26:14:58
at it we can understand that there exist uh three separate components that are connected with each other inside this
26:15:04
given graph and in this case the answer is going to be three and we need to return that. Now the idea is that first
26:15:11
of all based on this given input we will need to find a way to iterate over this given graph. Now to iterating over this
26:15:18
given graph can be a little bit tricky and the best way to do it in any computer language is to use adjacency
26:15:25
list or adjacency matrix. So you can we can use either one of them. So in this
26:15:31
case we are going to use adjacency list. Usually we use adjacency matrix when the number of edges are far more than the
26:15:38
number of nodes and we don't have any clear indication that that would always be the case in this scenario. So it's
26:15:43
better to go with adjacency list. Now once we have our adjacency list it becomes easier for us to iterate over
26:15:50
these given nodes. Right? So we have solved a part of problem but the other part of problem is that we need to find
26:15:55
that how many number of connected components there exist. Now in order to do it uh basically we need to find a way
26:16:02
to keep track of whatever the nodes we have visited so far and uh the best way
26:16:08
to do this is to create a hash set. So suppose we create a hash set and uh we
26:16:15
keep track of all the visited nodes that we have we have visited so far. Now the
26:16:20
approach we are going to use is that initially we are going to start at the zero position. Now from the zero
26:16:26
position we are going to run a DFS in this case. Then why DFS? Because the DFS
26:16:32
has a very particular property that it starts iterating from one element and it
26:16:37
will continue to iterate till it can reach all the subsequent elements or all the subsequent neighbors of this initial
26:16:44
uh uh element. So we are not going to stop up until then. And how we are going to use visited hash set is let me show
26:16:50
it to you. So essentially we will start our function with the zeroth position. We are first of all going to check that
26:16:57
whether the node we are currently visiting is it present in our visited hash set or not. So zero is not present
26:17:03
right which means we will have to add zero over here. So we add zero over here. Now uh and at the same time we are
26:17:09
starting our DFS function from this zero position. So we are going to have a variable called counter and initially
26:17:16
this counter is going to be initialized at zero. But now since we have started our DFS function so we are going to
26:17:23
initialize our counter at as one. Now uh from this uh zeroth position we are
26:17:28
going to see that okay it has a neighbor one. So we will check that whether one exists in the visited hashet or not. It
26:17:34
does not exist. So we will add one over here. So now this one has been visited and then we have we see that one has a
26:17:41
neighbor two. So again we will uh come back at two. Uh two has not been visited. So we will add the value two
26:17:48
over here. Now uh all the nodes in in this case have been visited that zero
26:17:53
has been visited one has been visited and two has been visited which means we don't have any more nodes to go to. So
26:17:58
we will just end our loop over here and now in our adjacy list because we have
26:18:04
already uh checked this zero one and two nodes. So we won't be doing anything for them because they have already been
26:18:10
visited. Now we will come at this node number three. Now again this node we are at this node number three and this has
26:18:17
not been visited and this is a new starting for the DFS function. So every time we do that we are going to uh
26:18:23
increment our counter function. So now the value of counter is going to be two.
26:18:29
So we will add the count to to be two and again we are going to repeat the same process. So this three has not been
26:18:35
visited. So we would we will add an entry over here called three. Uh from this three it has neighbor four and
26:18:41
five. So again four and five have also not been visited. So we will add an entry over here. And once all of them has been visited which means that we no
26:18:48
longer needs to iterate over these nodes because they have already been visited and their count has been accounted for.
26:18:54
And because they were connected so we only need to in increase counter once when we start the DFS function. We do
26:19:01
not want to increase the counter for all the nodes that are present. And once that is done so these all nodes are
26:19:07
taken care of. Now we are at node number six. So again we start the DFS functions from the scratch. So we will have to
26:19:14
increase our counter. So we are going to going to increase our counter to uh value number three. And now we are going
26:19:21
to add the values to hashet inside our hash set. We are going to add value number six. So we are done with
26:19:28
this one. And now we visit value number seven as well. And we are done with this one. So now essentially we in the in our
26:19:34
visited set we have visited all the number of nodes that were originally given as part of input and uh at the end
26:19:41
of this we simply need to return whatever the value of counter function we have found. So in this case the
26:19:47
counter we have found is three and this would be our answer. So basically this is the simplest approach. It's very easy
26:19:54
to understand very easy to uh explain in any interview and I don't know why lead code put this as a medium problem. This
26:20:00
should have been easy problem as I mentioned it from the beginning. Now if we calculate the time and space complexity in terms of time complexity
26:20:07
essentially we are doing uh couple of things over here. So first thing we are doing is we are creating an adjacy list.
26:20:14
Then after creating this adjacy list we are iterating over all the values that are present inside the adjacency list in
26:20:20
uh form of graph. So the time complexity in this case is actually going to be big of v + e where v represents the number
26:20:27
of vertices or nodes and e represents the number of edges because at any given moment we will have to iterate over all
26:20:33
the number of nodes and all the edges that are present. Uh in terms of space
26:20:38
complexity so for the space complexity essentially it's going to be the same. It's going to be big of v + e and why
26:20:45
because we are storing this uh adjacy list which is essentially the
26:20:51
combination of vertices and edges and we are also storing this visited hash set. So but in visit in this visited hash set
26:20:58
we are only storing the all the vertices. So this is actually bigo of v only. So essentially the space
26:21:05
complexity is going to be bigo of v plus e for adjacy list plus bigo of v. But uh
26:21:12
generically we can write it as big of B plus C. Any interviewer would be satisfied with this answer.
26:21:21
So first of all we are going to create a variable counter and we are going to initialize it to value zero. And now we
26:21:27
will initialize an array called visited. And I know that I mentioned that we are going to use a hash set but we can also
26:21:34
use an array as well. And uh initially we are going to initialize this array with the size n. uh the reason we are
26:21:41
not using hashet is because uh it was causing some issues with uh in Java by passing by reference and passing by
26:21:48
value. So I'll try to probably work upon that uh separately. And now we will
26:21:53
create an adjacency list and we are going to store uh all the nodes and
26:21:58
edges inside our adjacency list.
26:22:04
We will run two for loops. One to add all the nodes and one to add uh all the edges.
26:22:12
And now we are going to iterate over every single node and we are going to check that whether that node has been
26:22:18
visited or not. If not we are going to initialize uh we are going to call basically our DFS function and we are
26:22:25
going to increase the counter as well. And when this for loop ends essentially
26:22:31
we only need to return whatever the counter we uh whatever the result of counter variable we got. Okay. And now
26:22:38
let's create our DFS function. So first of all we are going to mark the
26:22:44
current node as uh one.
26:22:50
So we know that we have already visited this node.
26:23:01
And now we are going to run a for loop for all the neighbors of this particular node. And we are going to call the DFS
26:23:08
function again recursively. And notice that we are only calling DFS
26:23:15
function for all the nodes that we haven't visited. And uh this should be it. Let's try to
26:23:23
run our code. Okay. Seems like our solution seems like
26:23:30
our solution is working after bunch of different uh compilation errors. Let's try to submit this code.
26:23:37
Yeah, some solution seems to be working as expected and uh I will be posting this in the comments so you can check it
26:23:43
out from there.
26:23:51
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do a very important lead
26:23:58
code graph problem. Graph valid tree. Basically we are checking that whether the given graph is actually a tree or
26:24:04
not. And this question has been asked in bunch of different top tier companies uh companies like LinkedIn, Google, Amazon,
26:24:10
Bloomberg, Microsoft and Facebook. So these are my dream companies. So I'm
26:24:15
paying my utmost attention. I hope you like you enjoy the video. Okay. So this is a lead code medium
26:24:23
problem and we are given n number of nodes. We are also given a list of edges
26:24:28
and we are told that these edges are actually undirected edges. Now we need to see that whether the given graph is
26:24:34
actually a valid tree or not. If it is a valid tree, we'll return true. If it is not a valid tree, we'll return false.
26:24:40
And we are also given an example to understand this problem. Like in this example, we are given these five nodes and we are given some list of edges.
26:24:47
Based on this list of edges, we they have shown that it this could be a pictorial representation and over here
26:24:53
they are saying that yeah this is a valid tree. So that's why they are returning true. Now the question is in order to understand this first of all we
26:25:00
will have to understand that what is the relationship between any graph and a tree what is the difference between a
26:25:07
graph and tree and how can from the given input we can identify that okay this is a valid tree or not right that
26:25:13
every single tree is also a graph but that is not the case for every single
26:25:18
graph that it will always be a tree because if I if I put it in ven diagram
26:25:24
essentially graph is actually a supererset and it tree is just one of
26:25:30
its subset. So this can be a tree and uh this is a graph.
26:25:37
There are lot of cases lot of real life cases to understand that as well like uh
26:25:42
the person who got slapped by Will Smith is always going to be a human but not every single human has been slapped by
26:25:49
Will Smith. It is something in that kind of relationship. Right? Now the thing is what are the differences between a graph
26:25:55
and a tree that inside the tree all the components are connected
26:26:02
or all the nodes are connected. There is no restriction for graph that
26:26:08
all the nodes should be connected. And the second difference is inside the
26:26:14
inside any tree we will never encounter any loops. So we can just say no loops
26:26:21
while inside the graph there can be loops.
26:26:28
Let's try to understand this with some examples. Is is this a valid tree? Actually yes
26:26:34
this is a valid tree because notice over here that from one node like every single nodes are connected with each
26:26:40
other and we do not we do not find any single loops. Well thing is say for an example in this case if I had an
26:26:47
additional edge something like this I can clearly see that there exist a loop between these four uh nodes and because
26:26:54
we have identified a loop we can clearly say that this though this is a graph but this is not a tree.
26:27:01
Now let's take another example. Now this is a valid tree like all the
26:27:07
nodes they satisfy these two properties that they are connected and there are no loops.
26:27:13
The same graph if I had some components like this some additional nodes though
26:27:19
they are not connected with all the nodes they are connected with each other or there there are some isolated nodes
26:27:24
something like this if this is the case this will always be true that okay this is a graph we can put put it in the
26:27:31
category of graph but this will not be a tree and uh in this case we'll need to return false now before we move on
26:27:37
towards solution I just have a simple request if you see lot of people they watch my content but they actually not
26:27:43
subri subscribed to my channel. It takes me a lot of time and lot of effort to make these kind of videos and uh I would
26:27:49
really appreciate if you can just show your support and uh subscribe the channel like
26:27:54
now this problem actually can be solved in so many different ways and I'm going to show you few different ways on how we
26:28:00
can do things. Now the question is what we need to find basically basically we
26:28:06
need to find that whatever this given input is is this a valid tree or not. In order to find that whether it's a valid
26:28:11
tree or not, we need to check two things. Whether all the nodes are connected and uh if there are any loops
26:28:17
or not. Right? So what I'm suggesting is that we break this problem in two parts.
26:28:24
In the first part, we check that what could be the different ways. We can see that whether these nodes they are
26:28:29
connected or not. If they are all connected, we are good. And if they are not connected, we can return uh false
26:28:36
immediately that this is not a valid tree. And once that is done we will find all the ways on which we can identify
26:28:42
that whether there are any loops or not. Right? So first let's uh go with the
26:28:47
first approach. Now our aim is to check that whether all the nodes are connected or not. What could be the different
26:28:53
things we can do over here. In order to check that essentially what we will need to do is we'll have to traverse over
26:28:59
whatever this given input graph is. Now traversing over this given input graph based on the structure we are currently
26:29:05
given in the input is going to be a little bit tricky. uh based using this uh num number of nodes and edges. So the
26:29:11
question is like first thing we need to do is we will need to convert this given input in either adjacy list or adjacency
26:29:18
matrix. Either of them can be used and it it will work perfectly fine. But in this
26:29:24
case I will suggest to use adjacency list. We only use adjacency matrix when
26:29:29
there are too many edges and we don't have any clear indication in this case that there would be too
26:29:35
many edges and uh we we would try to use uh an adjacy list right
26:29:43
so now we are trying to check that whether all the nodes are connected or not
26:29:49
and we have already created our ad agency list now what I'm suggesting is that through
26:29:56
this adjacy list we know that we would be able to iterate over this given input and through this given input what we do
26:30:04
is we create a hash set inside the hash set initially it would
26:30:10
be empty whenever we are at any point iterating over any single node inside
26:30:16
this given hashet we will check that whether that particular node already exists in the hash set or not if it does
26:30:21
not exist we will add a new entry inside the hashet and at the And once we have
26:30:27
traversed all the values inside the given input uh through this adjacy list what we are going to do is we are going
26:30:33
to check that what is the total size of hash set and what is the total number of n given. If both are same we can
26:30:40
conclude that from any single point we are able to reach to all the other elements and because we were able to
26:30:46
reach to all the other elements uh all the elements are connected and uh we at least satisfy one condition. So let's
26:30:53
see that how it would work. Suppose uh in our adjacy list we start traversing through this position number one. Right?
26:31:00
So initially we check that whether this value number one exists in the hash set or not. It does not exist. So we'll add an entry over here that okay uh value
26:31:06
number one. Now through this value number one we can traverse in two direction. We can either traverse to the
26:31:12
neighbor on the right or neighbor on the left. So let's say that we go to this node number zero. Again we add zero.
26:31:19
From this zero we go to node number two. Again we come to two. Now from this two we can't go anyway forward right but the
26:31:25
thing is uh we we still need to go back we need we'll need to do backtrack we'll go back to one again through one we will
26:31:33
go back to three now uh at this three this is not added so we add it over here from this three we will go to four so we
26:31:41
will add four over here from this four again we will do a backtrack and we would come back at three and then we
26:31:46
will come to five and then we will add five over here now at the end of this hashtag we are able to iterate over all
26:31:53
the elements inside the given input, right? And we check that what would be the size of this hash set. So, so size
26:31:58
of this hashet would be six and what is the given n? So, n is also six. Which
26:32:04
means in this case we are at least able to conclude that this given hash set is actually satisfying our condition and
26:32:11
inside this given graph all the nodes are connected.
26:32:19
So, we are good. Now suppose in this case if we had an now suppose in this case if we had another node something
26:32:25
like this and this was not connected to any of them basically this would not
26:32:31
have been entered inside our hashet and our n in this case would have actually been seven rather than six. So we can
26:32:37
clearly see that if our size of our hashet is going to be lesser than whatever the number of n we have. If
26:32:43
that was the case, we could have returned false immediately because we f found that there exists some not
26:32:49
connected component and uh which was not the case in this case. So this is one of
26:32:54
the very good approaches to identify that whether the graph is connected or not. Okay. Now we have taken care of the
26:33:01
first part and now we need to take care of the second part that we need to check that whether in the given graph does there exist a cycle or not. So first
26:33:08
thing that comes to our mind is that why don't we use uh the visited hashet that we have we have already created and in
26:33:15
that visited hashet what we are going to do is at any point in time we are going to start exploring from one of the node
26:33:21
in the given input graph from that node we are going we are not going to stop exploring till we exhaust all the
26:33:28
neighbors of this particular graph and at every single time we are planning to
26:33:33
come to next element we would first check that whether that element exist in the visit hashet or not. If it exists,
26:33:39
uh then we would we would consider that there exists a loop and we would break out of it. If it does not exist, we
26:33:44
would add that entry over here. So, first we will add we will start traversing this value number zero. So,
26:33:50
it is it does not exist in visited. So, we will add an entry over here. From this zero, we will uh we'll start
26:33:56
exploring its neighbor. So, one of its neighbor is uh this value number one. And remember that we are going in depth
26:34:03
first search. So we will not stop until we exhaust all the possibility in one direction before going to the other
26:34:08
neighbor. We could do it breath for search way as well. Uh it's up to us. Now from this one again depth for search
26:34:15
we see its neighbor that there is a neighbor two. So we add an entry over here uh because it does not exist. Now
26:34:22
remember that this is actually an undirected edge. So what does an undirected edge means? Undirected edge
26:34:28
means that from zero we have an edge to go towards one and from one we have an edge to go towards zero. Same goes from
26:34:36
one that we have an edge to go towards two and from two we have an edge to go towards one and same goes from uh two
26:34:42
that we can go to zero and we can come back. Now over here from this position number two because we have an edge that
26:34:50
goes to zero we can consider that zero is also a neighbor of two. In this case from this two we will try to go to the
26:34:56
zero and the moment we try to go to the zero we will see that okay it has already been visited it is part of this
26:35:01
hash set. So we would say that okay there exist a cycle and uh we are pretty happy with ourselves that hey we have
26:35:08
identified a cycle and now we are done with our case. The thing is this is actually a wrong approach and the reason
26:35:13
why it is a wrong approach that it is wrong approach because there exists this undirected edge and let me show you by
26:35:19
an example that what could be the problems if we keep using this visited hashet only and uh how can we uh how can
26:35:29
we find false positives. So suppose we are given an example like
26:35:34
this that uh 0 calls 1 and uh two and
26:35:41
that's it. This is the input we are given right and now we don't have any entry inside our hashmap. Now the thing
26:35:47
is all the edges are undirected edges. Now because they are undirected edges we can represent them in different manner.
26:35:53
So let's represent them in slightly different manner. So from zero we have an edge that goes towards one. From one
26:35:58
we have an edge that goes to zero. Same goes from 0 to two and two to zero. Now
26:36:03
initially we start traversing from this zero. Now we we have our algorithm that
26:36:09
initially we are going to add the entry to visited hashet. So zero does not
26:36:14
exist. So we add the entry towards our visited hashet. Now from the zero we
26:36:20
need to check all of its neighbor before we move on to some other node. Now from this zero first of all let's say that we
26:36:25
go down this path and we check its neighbor two because there exist an edge like this we are able to check its
26:36:31
neighbor right so we are at this position number two now at this position number two we don't have an entering the
26:36:37
visited hash set so we enter an entry over here that uh this is two now from
26:36:42
this two again we will need to repeat the same process that we will need to uh check for all the neighbors or all the
26:36:48
edges that two this two can point to. Now it does not have any edges that go further but it has an edge that goes
26:36:54
back to zero. Now the thing is in this case again we will use our same logic.
26:37:00
So from this two we can still go to zero. So we will check that whether we
26:37:06
have visited this element zero or not. And over here we find that hey we have already visited this element zero. Which
26:37:11
means by our logic that we were previously trying to impose, we would have we could have said that okay we
26:37:16
have we have found a a cycle a cycle that looks like 0 to two and two to back
26:37:23
to zero and we in this case say that hey we have found a cycle and this is not a
26:37:28
tree and we will need to return false and blah blah blah. The thing is this is actually not the case. And why it's not
26:37:34
the case is because of this correlation of having an undirected edge that is
26:37:39
causing all this problem which means that we cannot rely only on having a visited hashet. uh if we do that then
26:37:47
essentially we're not we are not going to be able to find an answer because in this case we know that from there does
26:37:53
not exist an edge and from this uh two we are coming back to zero only because
26:37:58
there exist an undirected edge from this two to zero and that's why we can consider this 0 to be two's neighbor but
26:38:04
in reality this zero is actually parent of this uh child 1 and two so if that's
26:38:12
the case why are we still doing doing things like this. What could be a better approach we can use to find that what
26:38:18
would be the solution to detect these cycles.
26:38:24
There are a couple of different ways where where you can tackle this problem. One way to tackle this problem is that
26:38:29
initially remember the only reason we are causing this problem is because there exist an undirected edge which
26:38:35
means that there exist uh two directed edges from any two nodes. So what we can do is we can put a condition that at
26:38:42
from any point if we travel from this one to is zero or two if we are able to
26:38:48
travel one in one direction we would get rid of the remaining edge and let's see
26:38:53
that how it would work. So what I'm proposing is that initially
26:38:59
initially we are at this zero position. So we check in our visited hashet we don't have any entry. So we add an entry
26:39:06
over here that okay we are at the zero position. Now from the zero first let's say we travel to one which means that
26:39:12
now we have traveled from 0 to one in this direction. So our aim is that we get rid of this uh reverse edge in our
26:39:19
adjacy list. So if we get rid of that now we are at this position number one. At this position number one again uh we
26:39:26
add an entry over here in our vis visited hashet. Now from this position number one what we have to do is we'll
26:39:31
have to check that what are all the neighbors that we can travel to or all the children we can travel to. But this
26:39:37
one does not have any neighbor or children. So which means we don't have to worry about anything. So over here we can say that okay from this one we can't
26:39:43
go anywhere. But thing is there still exists some uh some nodes that we haven't traveled to and we are using
26:39:50
either BFS or DFS in any manner to traverse over entire graph. Right? So
26:39:56
which means that we will have to do a backtrack. So now from this one we do a backtrack. Now again we end up at this
26:40:03
zero. But the thing is in this scenario remember we are not ending up at this zero because from one there existed an
26:40:10
edge like this where we consider zero to be one's neighbor. We are coming back to this one because we are using
26:40:16
backtracking uh through any BFS or DFS algorithm. Uh we can we can implement
26:40:23
this recursively or iteratively doesn't matter in any scenario we will have to iterate over all the nodes that are
26:40:29
present inside the given graph. And since we haven't traveled all the nodes that's why we are coming back to the
26:40:34
zero. So again this would be a new entry in the visited hash set. So again we
26:40:42
come back at the zero and this zero we check that okay we have already explored one of the neighbor of the zero. But we
26:40:48
still have to explore another neighbor. So again we repeat the same process from the zero we explored another neighbor of
26:40:54
zero. we come back at two and immediately we get rid of this uh this
26:41:01
edge that was coming back to it and then we add an entry over here that okay we are at this position number two. Now
26:41:08
from this two again we don't have any more neighbors to go to. So now we have explored all the neighbors of one so we
26:41:14
can mark one as being done. Uh we have explored all the all the neighbors of two so we can mark two as being done.
26:41:21
And now we come back at the zero and we can mark zero as being done because we have explored all the neighbors of zero
26:41:26
possible as well. And in any scenario we did not find any single loop because we did not find repeated value inside our
26:41:33
visited hashtag. So we can determine that there does not exist a cycle and which means in this case we can return
26:41:39
true because there are no cycles. So we can say that there is no loop for this one. And the only reason we are able to
26:41:47
come up come up to this conclusion is because at every single position we were removing the edge where in one direction
26:41:54
we have already traveled. So that is one way to take care of this problem and uh this solution would work as expected as
26:42:02
as well. Right now the thing is there could be another solution where we can use the little bit different logic a
26:42:08
little bit different data structure and we can do things in better manner and let's see that what would be that
26:42:13
approach. So the second approach is that rather than
26:42:18
using this visited hashet we don't have we don't need to do anything with this visited hashet let it be used for the
26:42:26
purpose of counting that whether all the elements are uh connected components or not. uh what I'm proposing is that we
26:42:32
created another data structure a hashmap and in that h in this hashmap what we
26:42:39
plan to do is uh we as a key we have parent
26:42:45
and as a child we as a value we have the value of its children. Now let's see
26:42:52
that how could how can we use this combination to do things a little bit differently. So over here let's say that
26:42:59
we are given a graph like this that 0 1 2 3 something like this right. So 0 is
26:43:05
connected to one one is connected to two is connected to three and now we have this three connected back to this one as
26:43:12
well which means that there exists a cycle over here. Now because these are undirected edges which means that they
26:43:19
are birectional edges as well. So from this zero we can go to one. From this one we can go back to zero and blah blah
26:43:25
blah what not. So initially let's say that we are at the zeroth position. From the zeroth position we starts exploring
26:43:31
its uh neighbor or children or whatever we want to call. So the moment from this zero we are able to reach to this one.
26:43:37
We would add an entry over here in this hashmap. And the entry we are going to make is that uh zero is actually a
26:43:44
parent in this case. And one of the children that we could find for this zero is actually node number one. So
26:43:50
node number one is a children of zero and just stay with me that why we are using this approach. Now again from this
26:43:57
node number one we need to explore its neighbors right. So what are the neighbors of this node number one we can
26:44:04
explore neighbors based on the number of edges that goes out from this node number one. So from this node number one
26:44:10
we actually have two edges that goes out. First edges that from this node number one we can go to node number two.
26:44:16
Now we check in this hashmap that does node number one exist. node number one does not exist as a key. So we add an
26:44:21
entry over here. So we add we say that okay parent is one node number one and from this node number one we can
26:44:27
actually travel to node number two. So we are good with that. Now again from this node number one we still have
26:44:32
possibility that we can go back to this node number zero. So again we check in this hashmap okay that whether there
26:44:38
exist an entry for this node number uh zero that we are trying to reach.
26:44:43
Remember this very importantly. We will check that whether this node number zero that we are trying to reach from this
26:44:49
node number one does that exist in the hashmap or not. Okay. So zero exist in this hash in this hashmap. Again we
26:44:55
check that from this one we are trying to reach to this zero. Is this one one
26:45:00
of the children of this node zero or not? In this case yes one is the children of node number zero. If that is
26:45:06
the case we can identify that this connection from 1 to 0 is actually not a cycle. It's just a trivial loop and that
26:45:14
is being caused because there exist an undirectional edge on both the sides. So that's why we will ignore this case. We
26:45:20
will ignore this connection. We are not removing the edge. Again remember we are not removing the edge. We are just
26:45:26
ignoring this case because in the hashmap we are able to find that okay this 0 to one connection is actually
26:45:32
just a trivial cycle and we move on with our life. So from this one again since
26:45:37
we have reached to this two right and two is not existing and uh two is one of the children of one. Now again we are at
26:45:44
this position number two. Now again from this position number two what are the different ways we can travel? We can
26:45:49
either go back to one or we can go to three. Let's say that we go to three first. So we check that whether three exists inside the hashmap. Three does
26:45:56
not exist which means we can create an entry that where two is a parent and three is a child. We are good with this
26:46:02
so far. Now again from this two when we try to check that from two we are trying to go back to one is that is that a
26:46:07
cycle. So first we check that whether this one exist in the hashmap or not. So one exist in the hashmap over here and
26:46:15
two is one of its children. So because two is one of its children we are going to ignore this case and we are going to
26:46:21
ignore and because we are ignoring this particular we are just going to move on with our lives. Now we are at this
26:46:26
position number three. From this three we will check that okay what are the different places we can travel back to. So from this three we see that okay one
26:46:33
edge that goes to one edge that goes to two. First of all let's see let's explore this edge from three to two. Uh
26:46:39
so over here we will check that we are trying to reach to this node number two. So two already exist and three is one of
26:46:45
its children which means we are going to ignore this edge. So we don't have to worry about anything. Now again from
26:46:50
this three we check for this value number one. So okay from this three we try to see that whether we are able to
26:46:56
reach to node number one or not. Node number one has already been visited inside the hashmap and that's why we are
26:47:04
able to determine that there exist a loop inside over here from where we are
26:47:09
actually going back to one of the places that was actually uh not uh that is already been visited
26:47:18
in inside our hashmap and this hashmap acts as both it acts as
26:47:24
a visited uh hash set that we were implement we were planning planning to use and also it acts as a way for us to
26:47:31
determining that whether we are detecting the correct cycles or we are detecting the trivial cycles between the
26:47:37
unidirectional edges and this would be a way on how we can check the cycles which
26:47:43
means that the combination of this using this hashmap to identify that whether cycle exist or not and using this
26:47:50
visited node and iterating over using BF uh BFS or DFS inside our graph original
26:47:56
graph uh using these These two data structures we can actually com we can actually get rid of both of our cases
26:48:03
where we need to check that whether the graph is connected and we need to check that whether the graph contains any
26:48:09
cycles or not and once because we are able to do both of these things at the
26:48:14
end if we are able to reach to end node we will return true if we are not able to reach to end node we can return false
26:48:20
and this solution actually works perfectly fine there are no issues with this solution it is a very elegant
26:48:26
solution if you tell in any interview they are going to be very impressed with the depth and breadth of your uh
26:48:33
thinking capabilities. What are the space and time complexity over here and and can we do something better? So let's
26:48:40
uh first try to determine that. So space complexity in this case we we know that we will have to use the hashmap and we
26:48:46
will have to use the visited array as well. Inside the hashmap, we are going to iterate over all the nodes plus all
26:48:53
the edges. Which means that over here the space complexity would be big of v + e because we are iterating over all the
26:49:01
vertices and all the edges. The time complexity in this case would also be big of v plus e because we'll have to
26:49:06
iterate over all every single node and every single edge multiple times in order to come to this solution. But the
26:49:13
thing is we are not doing loop inside loop work. So which means we are not doing repetitive work at any given
26:49:18
moment. Okay. After such a long explanation, let's see that there can there be a
26:49:24
better approach. And yes, there is actually a very elegant, very beautiful solution where actually we don't even
26:49:30
have to go through all of these mess to detect that whether cycles exist or not.
26:49:39
In order to do that actually we need a higher knowledge of graph theory.
26:49:45
What do I mean by that? Okay. Uh at any given moment, suppose we are given a
26:49:50
graph like this that uh 0 1 2 3 4.
26:49:55
Suppose we are given a graph like this. Right? Now, if we want to identify that
26:50:01
whether this is a tree or not. Like in this case, we can clearly see that yeah, this is a tree. There is a very
26:50:06
legitimate scenario. There are no cycles. All the nodes are connected and blah blah blah what not. Everything is
26:50:11
good with this. Right? Can you notice an important property over here? The important property that I'm talking
26:50:17
about is if you count that what are the number of nodes and what are the number of edges does there exist a correlation?
26:50:24
Yes, actually there exist a correlation and the correlation is that suppose we are given the number of nodes equal to n
26:50:32
and if we are given the edges that are n minus one and we determine that all
26:50:38
nodes are connected.
26:50:44
If we determine that all nodes are connected because remember in our solution when we are trying to find
26:50:50
finding that whether the nodes are connected or not is much simpler. We simply need to use a hash set. We need
26:50:56
to iterate over whatever the given input we have and uh basically we can determine that okay whether the nodes
26:51:02
are connected or not. But checking for the cycle is slightly more complic
26:51:07
actually not slightly much more complicated because either we have two options and both options require us
26:51:12
modifying lot of things or managing a bunch of different data structures. Either we can choose to remove the
26:51:18
remove the edges like this or we can choose to create a hash set like this. In both the cases we are actually doing
26:51:24
lot of work. So what if we actually don't need to encounter that whether we need to find the cycles or not. If we
26:51:31
only encounter that whether the given nodes are connected or not. If that is true and at any given moment we identify
26:51:38
that okay all the nodes are connected and then we identify this property that whether the number of nodes that are
26:51:43
given and number of edges that are given if there is the difference between them is only one. If that is the case then
26:51:52
the given graph will always be a tree. Let's see in this scenario. In this scenario we can identify that okay from
26:51:59
this zero all the nodes are connected that this 1 2 3 and this four we are able to connect to all of them right. Uh
26:52:05
if how what is the number of nodes? So number of nodes in this scenario is actually
26:52:11
five. This 1 2 3 4 5. Now let's see that what are the number of edges. So if we
26:52:17
calculate the number of edges the number of edges is okay this is one
26:52:23
edge. This is two second edge. This is third edge and this is fourth edge. There are only four edges that are possible. If we have any more edges then
26:52:32
for sure there would be a loop because remember where would you add an edge in this scenario? You can add an edge over
26:52:37
here. Okay, there creates a loop. Uh let's say that you don't add an edge over here. Suppose you add an edge over
26:52:43
here. Again it creates a loop. Well, you don't even add an edge over here. You add an edge like this. So again this
26:52:50
creates a loop like this. Eventually as long as the the difference between the number of nodes and number of edges is
26:52:57
actually not exactly one and if the number of nodes are one number higher
26:53:03
than whatever the number of total edges are given. If that is the case and we determine that all the nodes are
26:53:09
connected then we can clearly say that okay everything is good with our life and we don't have to worry about anything. Why? Now why we need to check
26:53:16
that whether all the nodes are connected or not. The only reason we need to check if all the nodes are connected or not is
26:53:22
suppose we are given a scenario like this that we are given these three
26:53:27
uh these three nodes. Suppose we are given these four nodes right and in this four nodes so remember
26:53:35
our equation is that number of nodes and edges.
26:53:41
So if nodes are four and if edges are three so we can say that okay everything is good with our life. In this case the
26:53:47
number of node is uh 0 1 2 3. Okay. So total four four nodes we are good.
26:53:53
Number of edges 1 2 3. So this is also good. The thing is over here you can see that there exist a cycle over here
26:54:00
between these three edges. And why there exist a cycle? Because this particular node is not connected. So always at any
26:54:06
case we will have to check that whether all the nodes are connected or not. And once we identify that all the nodes are
26:54:12
connected we are good and then we can just uh wrap up our solution. So using
26:54:18
this solution actually everything becomes so smooth that if we calculate the time and space complexity the time
26:54:23
complexity in this case is actually big of n because we only need to iterate over the in given in number of nodes and
26:54:30
where n defines the number of nodes. If we calculate the space complexity, the space complexity is also big of n
26:54:36
because we only need to maintain a hash set uh to take care of all the number of
26:54:42
connected edges. So once we find out that what are the number of connected if all the elements are connected we can
26:54:48
immediately identify that whether this given graph is a tree or not. So let's move on towards coding.
26:54:59
Now first of all we are going to check that whether the given number of edges uh it's if it's length is uh one less
26:55:06
than the number of nodes or not. If that is not the case we can return false immediately.
26:55:13
So and if that's not if that doesn't happen we'll have to make an adjacency list. So we will create an adjacy list
26:55:20
so it becomes easier for us to iterate over the given input array.
26:55:29
So for all the given n we are going to treat them as vertices and all the values that are provided in the edges we
26:55:35
are going to treat them as edges basically.
26:55:40
Notice over here that we for every single edge we are actually adding two entries inside our adjacy list and that
26:55:47
is because the given edges are actually uh undirected. So that's why we will
26:55:52
have to add an edge for both the nodes. Uh so if there is an edge between 0 to
26:55:59
1. So we will have to create two edges and the those two edges would be zero uh
26:56:04
to one and from node 1 to zero. So and that is what we are
26:56:12
doing by the second for loop.
26:56:19
Okay. Now we will start iterating over the given graph inside the adjacency list. And uh I want to learn that how to
26:56:26
iterate over the graph using stack. So I'm going to uh do it using stacks and
26:56:32
uh I will be doing iterative depth first search. So first I'll initialize a stack
26:56:38
of integer value and just name it as stack
26:56:50
and uh we will also have to create a hash set of uh integers
26:57:00
called visited. Okay,
26:57:10
inside our stack we will add the first entry.
26:57:17
So we will add the node zero
26:57:24
and inside our hashmap visited we'll mark the first node as visited.
26:57:54
We will pop the first node that is inside our stack and then we will start iterating over its neighbors
26:58:02
and we'll see that if that uh neighbor has already been visited then we will simply ignore that case.
26:58:10
If that is not the case, we will start iterating uh we will start adding those neighbors to the to our stack as well.
26:58:19
And we will also add that neighbor to our visited hashmap as well.
26:58:31
It would be neighbor not node. Okay. And after this loop ends, we only
26:58:38
need to check that what is the size of our uh hash set. So if
26:58:45
or else we will return false and uh let's try to run the code.
26:58:55
Okay, seems like our solution is working. Let's try to submit this code.
26:59:00
Okay, our solution works pretty efficiently.
26:59:15
So the lead code problem we are going to understand now is called redundant connections. This is one of the most
26:59:21
popular questions in my opinion. Why? Because we are going to be dealing with graphs. On top of it, we are also going
26:59:27
to be learning about the trees, a data structure and we will learn a new data structure called disjointed set union.
26:59:34
So this problem contains two of the most popular data structures that we already
26:59:39
know and one very popular method that can come in handy in all sorts of different cases. So let's understand
26:59:45
what this problem statement is asking us to solve. First, we are given the difference between a tree and a graph.
26:59:51
The only difference between a tree and an undirected graph is that graph is
26:59:57
connected and it can have cycles. Meanwhile, tree is completely connected and it can never have any cycles. That
27:00:04
is the only difference. Now we are told that we are given a graph that was
27:00:09
originally a tree which means it could be possible that this graph may be not
27:00:15
connected or it may contain cycles. Okay, this is the important clue that originally this was a tree but then it
27:00:22
turned graph and now it is no longer tree which means there has to be some cycle existing inside this given graph
27:00:28
that contains total nodes and we are given the number of nodes as to be 1 to n. On top of it we are also given an
27:00:36
edges array that defines that any particular edge between any two array 1
27:00:41
to two. Now the thing is we need to return an edge that if we remove it so
27:00:49
that the resulting graph actually becomes a tree of nodes. That's it. So
27:00:54
we need to basically remove an edge that is part of the cycle that removing that
27:01:00
edge would not have any impact on all the nodes of this particular graph or
27:01:05
tree from being connected. And if we can remove that then basically uh there
27:01:11
should not be any cycles inside the existing graph. So let's try to understand this with few examples. Let's
27:01:17
say that we are currently given three nodes 1 2 and three. And we are given bunch of different edges between them
27:01:23
like this one. So in this case we can clearly see that this is not a tree.
27:01:28
Why? Because there exist a cycle inside this loop and wherever there is a cycle
27:01:34
it can never be a tree. So this is currently a graph. But imagine in this case if I just remove this particular
27:01:40
edge between the these three nodes then this is a very clear example of a tree.
27:01:45
Why? Because we can see that it currently has three nodes. All three nodes are connected with each other
27:01:52
because that is one of the conditions of being a tree that all the nodes has to be connected. On top of the connected
27:01:58
portion, we can also see that there are no cycles. Which means that removing 2
27:02:04
to three was one of the good decisions and in this case we need to return 2 three edge as part of the answer that if
27:02:10
we remove this edge then we can completely generate our answer. Now the
27:02:16
question comes that why do we only decided to remove edge 2 to 3. In this case if we had removed an edge let's say
27:02:23
1 2 3 then also the answer would have been perfectly fine. we would still have a tree that looks like this. But thing
27:02:29
is uh we are given in the problem that if there are multiple answers that we can remove the edge then we need to
27:02:36
return the answer that occurs in the last input which means like the last edge in this case made sense to be 2 3.
27:02:43
So that's why we remove 23 and not 1 2 3. Okay. So now let's we already
27:02:49
understood that what does the problem statement is asking us to solve. Basically we are given a graph that
27:02:55
contains bunch of different endpoints and amongst some endpoints there exist
27:03:00
some sort of uh cycle and we need to first of all detect that which
27:03:06
particular cells contain are part of the cycles or which edge is part of the cycle and then try to see if we are if
27:03:13
we are able to remove that edge or not. So if we once again take one more example in this case once again we can
27:03:20
see that removing this edge from 1 to 4 makes no sense now why because uh it
27:03:25
does not solve our problem. Number one this is there is still a cycle persisted and number two now we have unconnected
27:03:33
components. So this is no longer a tree. Uh this is always going to be a graph. So logically in this case the answer
27:03:39
once again has to be the same one that we need to remove the edge between this two and three. And by doing so we are
27:03:46
still going to have a treel like structure where we this one node is part of is parent of three different nodes
27:03:53
that is 2 3 and four and this is what we need to do. So once again we need to remove the this 2 to three. Now let's
27:04:01
understand that what I'm suggesting we use to solve this problem and for that
27:04:06
I'm suggesting to use a very popular data structure that is called disjointed set union. Now first let's understand
27:04:14
that what does this disjointed set union data structure is. So this data
27:04:20
structure actually has only has two properties but these two properties are very important and very awesome
27:04:26
properties. So first let's understand that what are the two properties. Basically disjointed set union allows us
27:04:34
to create a groups of set and uh that's it. So it can show us that if we have if
27:04:44
we have like bunch of different uh objects or values it can show us that that particular object belongs to which
27:04:50
group and if we provide two different uh objects it can sh say that whether those
27:04:56
two objects are part of the same group or not. So let me explain it to you then it would make more sense to you. Let's
27:05:02
say so I mentioned that this disjointed set union works with two methods. First method is a find method where if you
27:05:09
provide in some value then it can say that this value belongs to which group.
27:05:14
Okay. On top of it second one method is a merge method. So for the merge method
27:05:20
basically if you provide two distinct uh data structure like two distinct objects
27:05:26
that belongs to separate groups then it merges into one common group. So let's
27:05:31
see how it works. Let's say that currently I have these three nodes that are part of this one particular group.
27:05:39
Okay. And let's say that I have these two nodes that are part of this second second separate group. Typically in a
27:05:46
disjointed union set all the nodes are typically represented by some node that
27:05:52
is currently present already inside that particular group. So let's say we randomly select that this one is the
27:05:59
leader or the representative of this entire group. So we will call this as a group one. Okay. That every single node
27:06:07
that is currently present is being represented by this value one. So we can call this as group one. Same way over
27:06:13
here the representative is this value number four. So we can call this as group four where every single node is
27:06:19
being represented by group four. Now we know that we can do two methods. we have the find method and we have the merge
27:06:25
method. So let's say that if I try to do a find method and if I try to find value
27:06:31
number three. So if I if I try to find value number three all I'm going to get in the return is that this value number
27:06:38
three is part of this group one. So in the answer I would only get value as
27:06:43
group one and in the return. Why? because all of these nodes are
27:06:49
represented by their parent node or by the representative and representative in
27:06:54
this case becomes like the parent of all the nodes that are part of this particular group. Same way if I try to
27:07:01
do a find operation and if I want to find value number let's say five then in this case the answer we are going to get
27:07:08
back is going to be group four because this value number five is part of this group four. Now let's say that we wanted
27:07:15
to do a merge operation. So the moment we do merge operation between group one and group four then both of these are
27:07:24
going to be merged into one single set one common set. And how it is going to operate? Number one thing this property
27:07:32
is going to remain as it is. Now we have two options which uh who is going to be
27:07:38
the representative from 1 to four either one or four. We can pick whoever we
27:07:43
like. So let's say that in this case we decide that representative is going to be one of this common jointed group. So
27:07:50
how this group is going to look like that one is the representative. It already had values 2 and three. So it is
27:07:56
going to continue to have values 2 and three that represents or who has parent value as one. But same way now we are
27:08:03
also going to add one more node four whose parents or representative is now
27:08:08
going to become value number one. And for this value number five, it is still going to have four as one of its
27:08:14
parents. But now for this newly created group, if we try to find that any
27:08:21
particular character, let's say if we want to find value number three, then for value number three, we are going to
27:08:26
say that value number three is part of group one. So in the answer, we are going to return the value as group one.
27:08:33
Same way for value number five. If we try to do that in this case once again we are not previously we were returning
27:08:41
value number four but remember now value number four is also being represented by value number one. So once again for
27:08:47
value number five the same property is going to be inherited to value number five as well. And now for value number
27:08:53
five we are also going to say that this is part of group five. So this is the
27:08:59
whole concept of disjointed set union. The thing is why the hell am I
27:09:04
explaining you this concept? What does what purpose this serves us? Now let me show you that how we can use this method
27:09:11
to actually solve our problem and very effectively find or detect that whether
27:09:17
there exist a cycle inside any particular graph or not or cycle does
27:09:22
not exist. And remember whenever you have to find a cycle in an undirected graph then this is a very popular method
27:09:30
uh in order to do this one. So not only we are learning about the redundant connection lead code problem, we are
27:09:36
also learning a new method, a new algorithm, a new data structure with our existing tree and graph data structure.
27:09:43
And that's why this is a beautiful problem. Okay. So coming back to the solution now remember the problem
27:09:49
statement that we needed to find that amongst these three nodes. Let's say that if there exist a cycle like amongst
27:09:57
these four nodes, we don't know where the cycle exist. If there exist a cycle, we will need to remove the node that is
27:10:03
causing the cycle or sorry remove the edge that is causing the cycle and once we find that we need to return that as
27:10:09
part of the answer. So let's say that currently we are given this these four nodes. Okay. And we are we are being
27:10:16
told that these are the edges we are currently given. So what we can do is
27:10:21
currently we can create four separate groups and these groups are not connected with each other. So if we
27:10:28
create four separate groups how it is going to look like? We will have a group one, we will have a group two, we will
27:10:33
have a group three and we will have a group four. Currently these four groups are not connected with each other. So we
27:10:41
can actually have a disjointed union set that is currently present that
27:10:46
represents that for every single node who is the representative or who is the parent of that particular node. So if we
27:10:52
want to define that currently the we can have a parent array let's say and for
27:10:58
every single node we will try to define that who is currently the parent of that particular node. So since this one is
27:11:03
being represented by its own so the parent is going to be one. Same way the parent for this one is going to be two.
27:11:09
Same way the parent for this one is going to be three and so on and so forth. So currently all of these four
27:11:15
nodes are unique on their own. They don't share any parents so far. Now what
27:11:21
we are going to do is we we currently have four edges that we need to deal with and let's mark these four edges. So
27:11:28
the current first edge is 1 to 4. Same way second edge is 1 2 the third edge is
27:11:34
1 2 3 and fourth edge is uh 2 to 3. Okay. So logically uh if this is the
27:11:42
case now we currently have parent for each four separate sets. We are going to
27:11:47
go start iterating over the edges. For every single edge, we are going to check that what are the current parent groups
27:11:55
we have. And if we identify that they contain separate groups for both the vertices of this edges, then we are
27:12:02
going to do a merge operation. Okay, let's so let's start doing that and then you will understood. So currently we are
27:12:09
dealing with edge 1 to 4. Now for this edge to 1 to four we will have to check that which are the vertices involved. So
27:12:16
number one vertices is value number one. Number two vertices is value number four. So for both of these we will check
27:12:23
the or we will do a find operation that who is the parent of those particular sets. For one the parent is already one.
27:12:30
For four the parent is currently four. So both are separate sets. There is no
27:12:35
common commonality. So if there is no commonality we will do the merge operation over here. So let's if we do
27:12:42
the merge operation what will happen is we are essentially establishing a link between this node one and node 4. So by
27:12:50
doing the merge operation now we will have to select that who is going to be the representative. So let's say that we
27:12:55
are going to choose the smaller value as the representative. So I choose representative to be one. Now if I
27:13:02
choose the representative to be one which means now even for this four the parent is going to be one because four
27:13:09
is being represented by one and for the value number one the parent is going to be itself. So we will have to make some
27:13:15
adjustments to our parent array. So this value number one is going to stay as it is that it is currently the parent of
27:13:22
its own but for this value number four the parent is going to change and now this is also going to be represented by
27:13:28
value number one. Okay, we completed this operation and now we have made the
27:13:34
updation on the parent block and we also are done with this 1 to4 uh edge. So now
27:13:40
let's take care of 1 to2 edge. Once again repeating the same operation we have two nodes one and two and for both
27:13:47
of them the one has parent as one and two has parent as two. We can see over here but now since both are separate so
27:13:55
we will have to do the merge operation. If we merge these two cells once again, we are establishing a link between this
27:14:01
one and two. Establishing a link between 1 and two now, which means we are also updating the parent of this two to be
27:14:07
value number one. Okay. And now the next edge we currently have is once again
27:14:13
edge 1 2 3. So once again for 1 2 3 it currently has 1 and three as separate
27:14:19
nodes. If we take a look at the parents, it is going to be 1 and three. If we do the merge operation because they are
27:14:25
separate links. So if we do the merge operation, we are going to have our parents array that is going to look like
27:14:31
all four values are being represented by one because we are also establishing this link as well. Now this is our
27:14:39
parents array. All four values contain one. But we still have one more link that we haven't tested and that is this
27:14:45
link 2 to three. So let's do that. For this 2 to three, if we see we currently
27:14:50
have vertices 2 and three as part. But now if when we check for the parents we
27:14:55
can see that the parent is going to be common that is going to be 1 and one for both 2 and three. So this is going to be
27:15:01
common. The moment we identified common parents amongst any two vertices we can
27:15:06
clearly say that if we were to create an edge between these two nodes that edge
27:15:12
is already part or is going to be part of the common nodes that are already
27:15:17
connected by connected in a common set. So creating this new edge is only going to lead to create creation of cycle. And
27:15:24
the moment we identify any two nodes that share a common parent basically we
27:15:29
can just return that edge as the answer. And this is the whole solution basically. So you understood how
27:15:36
beautiful the solution was. We first of all understood that how how a disjointed
27:15:42
union set works. Then we understood that what is the difference between tree and a graph. Then we understood that how we
27:15:49
can use disjointed union set and its property to find or update the parent values or create new links between any
27:15:56
two vertices and then we find the edge that is causing all sorts of trouble and return that as part part of the answer.
27:16:03
So this is a beautiful solution and a beautiful approach. So now let's quickly see the coding solution solution for
27:16:09
this one. Okay. Now uh the problem the coding solution for this one is not so
27:16:15
complicated. So let's try to understand what is being asked us to solve. First of all we need to check that for any
27:16:20
particular given node we will have to define that what are all the different parents. So first we are going to
27:16:26
initialize a new array called parents and notice that we are setting the value as edge length + one. Now we are
27:16:32
starting to iterate parent from one not from zero because initially each node is
27:16:38
its own parent and we are being told that the current nodes we have are 1 to n 0 to n. So that's why we are starting
27:16:45
from one and we are marking all the values as their own parent which means all the nodes are currently individual
27:16:51
sets of their own. Then we are going to iterate through every single edge in order to find the redundant one. The
27:16:58
moment we identify a new edge we are going to break both the values in part of two nodes node one and node two. For
27:17:06
both the nodes we are going to be finding the parents of those nodes node
27:17:11
one and node two. And for that we are going to be calling our find method that we have defined. Next
27:17:18
we need to check that if at any given moment we identify that the roots are
27:17:23
same for both node one and node two we need to return that edge as the answer because that edge is causing all the
27:17:30
trouble and creating the cycle. If that is not the case then we need to update the root of that particular second like
27:17:38
the parent of second root to become the value of the first root and this is what
27:17:44
we are doing is the union or the merge function amongst our two values. So
27:17:50
let's quickly try to see the helper function we have created that where we can actually use to find that who is the
27:17:56
parent of that particular node. Basically we are simply checking that if the node is not the the node we
27:18:03
currently have if that is not equal to the parent node we are simply going to keep traversing up in order to find that
27:18:10
which is the parent node and we are going to be updating the value of the parent node. That's it. It's very simple
27:18:15
and uh we are returning that value. So basically uh we should be able to calculate everything. Now this is just a
27:18:23
return statement that is ideally just returning the value zero. Basically this this should never happen because we are
27:18:30
being told that for every single input we do have a graph that contains a cycle
27:18:36
and we need to return proper edge. So we should be able to find a scenario like this. Now let's quickly try to run this
27:18:42
code and see see if our solution is working as expected or not. Seems like our solution is working
27:18:48
beautifully. Let's submit this code and our code beats 100% of all the other
27:18:56
solutions which is awesome in terms of memory usage. It is exceptionally well.
27:19:01
So in both aspects this is doing wonders and uh this is a really good uh solution.
27:19:15
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. Graph problems
27:19:20
have always been a big no no for me. I have always been afraid of graph problems. But the thing is now I have
27:19:26
decided to take them heads on and uh today we are going to start doing more graph videos. So this is the first of
27:19:33
many graph problems to come and uh this question has been really popular with Facebook recently. It's been asked 44
27:19:41
times which is huge number. Also key other companies like Amazon, Google, Bloomberg, Microsoft, Twitter, they are
27:19:47
also asking this question. But the thing is Facebook for some reason has been really interested. So I highly urge you
27:19:53
to go and uh check this video if Facebook is one of your dream companies to join.
27:20:00
Okay, this is a lead code medium problem and we are given a reference node in a connected undirected graph. So first
27:20:07
let's understand the meaning of these two values. Suppose we are given a graph like this.
27:20:12
Notice that there are only four nodes and from any single node we can reach to all the other nodes in the given graph
27:20:19
which means that this is a connected graph. So this is what connected means and undirected graph means suppose we
27:20:25
are given a graph like this. Uh and we established that A is B's
27:20:33
neighbor which means that we can traverse from A to B and also we can traverse from B to A. So there is no
27:20:39
restriction regarding the direction of any direction of any edge between two
27:20:44
nodes. So we are given a reference point to that and we need we need to return a
27:20:50
deep copy of the graph. So what does a deep copy of the graph means that suppose we are given a graph like this.
27:20:59
So we need to return a graph like this
27:21:06
where if you see the values of the nodes they are all the same but the thing is
27:21:12
we are not using the exact same nodes. We are using different nodes with same
27:21:17
node values. Uh which means that this would be a legitimate case where we can
27:21:22
consider this as a deep copy of this original input. The thing is if we create a graph like this
27:21:30
over here we are using we are using these the same node to represent over here which means that we are not
27:21:37
creating a copy of this original graph we are just referencing this point to whatever value we had over here. So this
27:21:45
is not what we want to give. And also if we create some graph like this,
27:21:53
if we see the values of the nodes, the values remains the same. But the thing is the ordering is different that in
27:22:00
terms of neighbor selection and how they are perceived, they are different. So this is also a false case. We need to
27:22:07
return a copy of this exact same input just with the nodes that are copied from
27:22:13
this one. So at the beginning the most basic idea
27:22:20
we are going to have is that okay we are given an input we are given a reference point we know that the input graph is
27:22:26
connected which means that there are no loose ends that we have to worry about. So why don't we just traverse through
27:22:31
the uh in given input graph at every single node we start creating a copy of
27:22:36
it. We start creating the same sort of neighbor connections that we have in the original graph and then just try to
27:22:42
return the new graph. That would be a perfectly good logical sol rational
27:22:47
person would think and uh that sol that would be a good entry point to start our solution. But thing is we are going to
27:22:53
see that with that approach what would be the issue how can we remediate that issue and uh what would be the final
27:23:00
solution. So let's start. So first of all suppose in this given input we start at this one position. So we create a new
27:23:08
node one. Okay. Now from this one we can go to any neighbor. We can go to two or
27:23:13
we can go to four. Let's say that we go we go clockwise. So we go to two. So we create a new no new neighbor over here
27:23:21
called two. Again from this two we go to three. Uh and over here keeping the same
27:23:27
logic we create a new node. Now notice one thing that initially we had uh we
27:23:32
created a clone over here. We went to its neighbor again. We created a clone over here. We went to its neighbor
27:23:38
again. We created a clone over here. We will go to its neighbor. So basically for we are doing the same problem again
27:23:44
and again for different kinds of input. So that should immediately click in your mind that this we are going to solve
27:23:50
recursively. So just keep this in mind that this this is a very good way to use the recursive approach. And uh now at
27:23:58
this three again we go to its neighbor. So we'll create an edge and we'll create
27:24:03
a new node four uh for this one. So from this four again we go to its neighbor.
27:24:09
Again we go over here. But the issue with this approach is that for this our
27:24:14
recursion to end we need to have a terminating case. But in this scenario we are not terminating it anyhow because
27:24:20
the thing is the graph is connected. We are terminating in a scenario where if the graph is empty we return something
27:24:26
empty or something like that. But the thing is over here again we when we come back to this one we are still going to
27:24:32
see that okay this is one. We need to create the clone of it. We will create a clone of it again over here. Which means
27:24:38
that we are going to do we are going to overwrite whatever value we have which which would be the same value again we
27:24:43
would go to two we would again create another clone again we would go to three again we would create another clone
27:24:49
again four again another clone we so basically we are going to end up inside
27:24:54
the loop again and again infinitely this is almost like infinity warn is going to
27:25:00
snap his fingers something like this because we are completely uh destroying our computer's resources our company's
27:25:07
resources because it's an infinite loop. It's never going to stop. So, and the reason it's never going to stop is
27:25:12
because we are doing the repetative work again and again and again and that is the issue. So, somehow we need to
27:25:19
resolve the issue. So, how we are going to resolve the issue? Well, basically the idea is simple. If at any point
27:25:24
suppose we create an additional data structure in that additional data structure we keep track of whatever the
27:25:30
value we have traversed already or we have cloned already. If we know that
27:25:35
which means that initially when we start we are going to check in that new data
27:25:41
structure first that hey this element have I you have I cloned it already if I have cloned it already I would skip over
27:25:47
I would go to next element if I haven't cloned it already I would create a new clone of it and then I will put the same
27:25:54
entry in the hashmap first before I go to the next element. So that way when
27:26:00
after this first circle comes and when I come back to the same position I would
27:26:05
know that okay I have already calculated this one which means that I don't need to calculate it again and I can skip
27:26:11
over it. First of all let's create let's see that
27:26:17
what kind of additional data structure we are going to create where we can immediately find that whether we have visited any particular element or not
27:26:24
which means that we are going to do lot of searching. Hence we will need a data structure that is very quick and
27:26:30
efficient in terms of finding the uh any element that whether it contains that element or not. Uh and the answer is
27:26:37
pretty simple. If that kind of scenario happens we need to use hashmap or hashet or something with the hashing. We cannot
27:26:43
use the link list over here. It would work fine but it's going to add that much more additional time strain or on
27:26:50
our system. So make sure that you justify your reasoning. I mean in the
27:26:55
interviews people are not typically going to ask that why did you use hashmap this is a given but the thing is
27:27:00
that uh thinking should be clear in your mind that why you are using it and in
27:27:08
most of the graph problems uh typically hashmap is being used.
27:27:16
Now inside this hashmap we are going to store two values. So as a key we are going to store a node and as a value we
27:27:23
are also going to store the node. But thing is as the key we are going to store this input node and as the value
27:27:29
we are going to store the cloned node that we will create. So let's see that what what should be the algorithm for
27:27:35
our solution and how we are going to approach it. So initially we start at this position one. Now at this position
27:27:42
one first of all we check that whether we have this entry inside our hashmap or not. Okay, we don't have the entry
27:27:48
inside the hashmap because we can find it in constant time. If the entry does not exist, we first of all create a
27:27:54
clone node. Okay, clone node has been created. Now after creating the clone
27:28:00
node, immediately before even we check for the neighbors of this one, immediately we are going to add an entry
27:28:06
inside the clone node. So the value would be the cloned value that we have
27:28:11
created and the key would be the original uh input we are given. Now this
27:28:17
is done. Now we are going to check for this one's neighbor. So one let's say we end up at this neighbor number two. So
27:28:25
again for this neighbor number two first of all we are going to check that whether neighbor number two exists in
27:28:30
this hashmap or not. It does not exist. So we will create a clone. Now the clone has been created. First we will add the
27:28:36
value to the hashmap and after adding the value we would
27:28:42
again go again recursively do uh find for the two's neighbors. So in this case
27:28:49
uh the two's neighbor would be three. So we will create uh first we will check
27:28:54
that whether three exist in the hashmap. Three does not exist. So we create the node and then we create this one. Now
27:29:01
again we check for the value number four. Four does not exist. So again we create an entry inside the hashmap. We
27:29:07
provide the key value and then we create the clone node four again. Now for the fourth we again check for its neighbor.
27:29:14
So four's neighbor one neighbor is one which we already have it in hashmap which which means that now we can ignore
27:29:21
this case because we have already dealt with one. Now second neighbor for four is three which already exist in the
27:29:27
hashmap which means we can we can be dealt with it. Uh we go back two is already done. and one is already done.
27:29:33
Which means that now we are running out of neighbors to take track from inside the given uh original input. And we know
27:29:40
that the original input is completely connected graph which means that there is at no point there is a possibility
27:29:46
that there exists some value five over here that is part of this graph but it
27:29:51
is not provided uh using this connection because all the elements are connected
27:29:57
which means that this would be our final clone graph that we need to return. So
27:30:02
after the loop ends and the recursive termination cases trigger we can simply
27:30:08
return whatever the clone graphs we have found because from any single location
27:30:13
we are able to guarantee to reach all the other elements and once that that is
27:30:18
done essentially we are done. So this is a very effective solution. Basically all we are doing is just we
27:30:24
are traversing over the given graph and uh during the traversal we are doing
27:30:30
something. So in this case we are cloning it. Um we are using the hashmap to keep track of whatever the visited
27:30:35
elements that we have been through and uh this solution is pretty efficient. It's uh it's not the most difficult
27:30:42
problem in the world but the thing is I am very bad at graph problems. So and uh
27:30:48
I have always been scared of graph problems but the thing is now I have decided to spend more time on graph
27:30:54
problems because if you want to join Facebook you can't you can't even think about not doing graph problems okay so
27:31:01
today is first of many problems to come uh if we see the time and space complexity time complexity in this case
27:31:07
would be big of v plus e where v is the vertices and e are the number of edges
27:31:15
because notice that over here we are only doing this much work we are not doing any additional work. So that's pretty simple and in terms of space
27:31:21
complexity it would actually be of v uh in terms of number of vertices because over here we had four vertices and uh in
27:31:29
the hashmap we created four entries uh so whatever the number of vertices we are provided we are going to use that
27:31:35
and uh that would be our space complexity. So this solution is actually pretty efficient. uh the we are using
27:31:43
depth first search to solve this problem but even we can solve it with using
27:31:49
breath first uh search so it makes no difference in terms of time complexity
27:31:54
the thing is I just did this using depth first search next one I'm going to use breath first search maybe
27:32:03
so first of all we are going to create a new hashmap and we are going to name it visited
27:32:10
to keep track of whether we have already visited the node node or not.
27:32:16
Now inside the method first of all we are going to check that if the given node is null
27:32:23
which means that we can return the node.
27:32:30
Okay. And also we are going to check that if uh the if we have already
27:32:35
visited the existing node
27:32:41
then we are simply going to return whatever the uh value we have stored
27:32:49
inside the visited hashmap. Okay. If this is not the case uh first
27:32:56
of all we are going to create a clone node. So let's just name it clone node
27:33:08
and in inside the clone node we are going to give it the value of whatever
27:33:13
the node value that we currently have and we are going to assign a new array
27:33:18
list. We are going to add the new clone node
27:33:24
to the visited node. We are going to run a for loop for all the neighbors of existing node.
27:33:35
So inside the loop we are going to iterate over the neighbors of the existing node and we are going to create
27:33:40
the clone nodes for that and inside the current clone node we are going to put the neighbor as an array list. So,
27:33:51
and over here we are going to make the recursive call with the neighbor.
27:33:59
After this loop ends, we are simply going to return the clone node.
27:34:07
Let's try to run this code. Okay, seems like our solution is working. Let's try to submit the code.
27:34:15
Okay, our solution works and it works pretty efficiently. There is still room to make a lot of improvisation as we can
27:34:21
see that our solution is not the most efficient. But the thing is I'm really bad at graphs. So it took me a lot of
27:34:27
time to make this video because I need to understand very thoroughly by myself first before I can create the video. Uh
27:34:34
but soon I'm going to do lot of graph videos. So it's going to so my video
27:34:40
quality is going to improve and also my coding is going to improve. So, hope for the best and uh let me know in the
27:34:45
comments what do you think about the video and uh yeah, see you next time. Thank you.
27:35:01
Hello friends, hope you're having a fantastic day. So now we are going to do an awesome lead code problem called rotting oranges. We can see that this
27:35:07
one is a medium problem and also an extremely well-like problem. The statement is quite straightforward. We
27:35:13
are given an M crossN grid where each cell have one of these three values.
27:35:18
First value is zero that represents that there is an empty cell which means there are no values over here. Uh second
27:35:24
potential value can be one which represents that there exist a fresh orange on that particular cell in the M
27:35:30
crossN grid and next value is two which represents that there could be a rotten
27:35:36
orange or a bad orange placed in that particular cell. Now there comes the
27:35:41
interesting part that with every single minute any fresh orange that is four
27:35:47
directionally adjacent to a rotten orange becomes rotten. So after every
27:35:53
single minute iteration we will have uh we will start finding more and more
27:35:58
rotten oranges and they would keep on growing. Now we need to return the minimum number of minutes that must
27:36:05
elapse until no cell has fresh oranges. That is number one thing that we are
27:36:10
being asked. If that is the case, we need to return the minimum number of minutes. And if it is impossible to rot
27:36:16
all every single oranges, then we need to return minus one as part of the
27:36:22
answer. So let's try to understand this awesome lead code problem. Okay. So suppose this is one of the exampled
27:36:28
input that we are given. Now notice that the values are 2, 1, and 0 given in different sections of this 3x3 cell. Now
27:36:36
we know that value number two refers to a bad orange. So I have denoted that as
27:36:41
like B over here in this grid and one refers as normal orange. So I have just
27:36:47
marked O or like zero that represents a fresh orange. Okay, don't confuse this
27:36:52
with like value zero because value zero I have left it as empty because there
27:36:58
are no oranges or nothing on that particular place. So now let's focus on our input. Now the way we are given this
27:37:05
problem this is a bad orange. Now let's say that this is the current starting
27:37:10
position. So at minute number zero this is currently what is happening right now. But we know that after every single
27:37:17
minute all the oranges that are so adjacent in four direction to this bad
27:37:22
orange will start getting bad. So after 1 minute passes we are going to have two
27:37:28
more oranges that have gone bad and that are these two oranges. So we can mark
27:37:33
them as bad oranges and all the other oranges that we have are going to remain as it is. Uh this is this happens during
27:37:40
the first minute. During the second minute once again more oranges are going to get bad. So since this orange is
27:37:48
right adjacent to this one, this will go bad and this orange will go bad in the next minute. So this these two oranges
27:37:54
will go bad. So if we mark the number of bad oranges, it is going to keep on increasing in this fashion. And now we
27:38:02
are only left with two fresh oranges. And during the third minute basically we
27:38:07
are also going to have this orange go bad because notice that this is directly
27:38:12
adjacent to this orange. So during the third minute this orange will also go bad and all the other oranges we already
27:38:19
have they are bad. And during the fourth minute basically uh because the in the
27:38:25
third minute this orange is fresh but during the fourth minute this orange will also go bad. And now we don't have
27:38:31
any fresh oranges. So we can say that after four minutes basically every single oranges that could go bad they
27:38:38
have all gone bad. So in this case we need to return four as the answer. Now let's say for the same example we are
27:38:44
basically given one more scenario. Let's see that what would happen in this case. Well, we know that during the first
27:38:50
minute the adjacent orange is going to get bad. So now we are going to be left with two bad oranges and few other good
27:38:57
oranges. During the next iteration once again the same thing is going to happen. And now in this next iteration basically
27:39:04
this orange is going to go bad. So then we are going to be left with these three bad oranges and then these three good
27:39:10
oranges. During the next minute once again same thing is going to happen and basically we are going to be left with
27:39:18
uh this uh orange as becoming bad orange as well and all the other oranges would
27:39:24
remain good. And during the next iteration basically this orange will also go bad. But notice one thing that
27:39:31
uh despite all every single orange being bad we do not have any particular way
27:39:37
for this particular orange to go bad. Which means no matter how many iterations we take even if all the
27:39:43
oranges went bad this orange will still remain fresh. So in this case because we
27:39:48
cannot have every single orange becoming rotten we need to return minus one as the answer. So this is what is being
27:39:55
asked us to solve in this problem. Now I know this problem looks really interesting and really important in
27:40:02
terms of many different aspects. So first let's try to start breaking the problem down and start understanding
27:40:08
different things on what we can do to solve this problem. Let's say that in this problem we are given oranges like
27:40:15
this and all the other cells are simply empty. Logically what is the most simple thing we are going to do? Well, we are
27:40:22
we need this is the initial position. So, we are going to have a value called minute. And in this particular minute,
27:40:29
we are going to mark that all the minutes that has elapsed so far. So, during the zero minute, this is the
27:40:35
position. So, during the first minute, what is going to happen? We are going to start noticing that this orange will go
27:40:41
bad. Okay? Then during the second minute, this orange will go bad. During the third minute, this orange and during
27:40:48
the fourth minute, this orange will go bad. So this case it's going to take four minutes for every single orange to
27:40:54
get rotten. So the thing is we can visualize it very quickly and very easily. But how can we implement this
27:41:01
programmatically? So that's where few important concepts come into the place that let me start describing. Number one
27:41:08
concept is that basically for every single position we will have to
27:41:13
understand that what is the rotten or bad bad orange and then we will have to
27:41:19
start iterating from that particular element. So, so far we were lucky that the very first element was actually a
27:41:25
rotten element. But let's say in the same scenario, instead of this being rotten, what if this was a rotten
27:41:31
orange? Once again, the answer would still be 4 minutes. But in this case, we would have iterated over all of these
27:41:37
cells before finding this rotten cell before we start branching out. So that is number one thing that we need to
27:41:44
first of all find that what is a rotten uh uh orange. Okay, that is number one
27:41:50
thing. Next thing is the moment we find the rotten orange what we do is we start branching out. But the question is are
27:41:57
we branching out in the depth first manner or a breath first manner? Well
27:42:05
logically in this case we are actually iterating in the breath first search manner because for every single node
27:42:10
that we iterate over we try to iterate all of its neighbors before visiting or
27:42:16
before visiting their neighbors. And let me give you a very simple example for that. Let's say in this example uh
27:42:23
during the very first iteration we simply visit this neighbor. Okay. So we are going to mark this as a bad orange.
27:42:29
But in the next iteration rather than going in one particular direction we are going to branching out in two directions
27:42:36
and marking both of these as bad apples. and then after exhausting all the
27:42:41
neighbors of this particular orange then only we will start exploring more neighbors of these remaining oranges. So
27:42:48
this is also another uh important point to be understood. Okay, that we will actually have to use breath for search
27:42:54
in this case to solve this problem. Okay, we took care of two items. Now let's try to understand that how we are
27:43:01
going to keep track of the number of minutes. Well, logically the answer is quite straightforward that whenever we
27:43:07
have to make any single new BFS call, we are going to keep track or keep incrementing the number of minutes that
27:43:14
we will have to make. So this would be our minute counter that we are always going to update with every single new
27:43:19
BFS call we make. Now we know that in order to use a breath for search we will have to use a cube and logic is quite
27:43:26
straightforward that first of all we are going to iterate over all the oranges that we are given and try to find all
27:43:32
the bad oranges we have. In this case we only have one bad orange but it could be possible that we are we may be given
27:43:38
multiple bad oranges. So let's say that we are only given just one bad orange. So we are going to put this bad orange
27:43:45
in the cube and with every single iteration we are going to branch out in
27:43:50
all four directions from this bad orange. The moment we identified a good
27:43:55
orange we are going to mark that also as a bad orange and push it down the queue
27:44:01
in order to be processed in the next iteration and that next iteration will happen in the during the next minute. So
27:44:07
this is the second important logic that we will have to understand that how we are going to be processing the cube. Now
27:44:13
comes the interesting question that how would we know that we have actually isolated or ex completed every single
27:44:20
oranges that we could and whether we need to return the minutes or do we need
27:44:26
to return minus one. So for that during the first time when we are actually iterating over to find all the bad
27:44:33
oranges and pushing them on the cube at the same time we are also going to have a counter that stores the number of good
27:44:40
oranges we have and what we are going to doing is that let's say in this case we realize that we have four good oranges.
27:44:47
Now every single time we add one value to the B we are going to reduce one
27:44:52
element from the good oranges. We are going to be doing the breath first search as long as that we can we are
27:44:58
able to reach some oranges and then once we get out of our loop we will try to
27:45:03
check that hey uh do do we do we still have any more good oranges. So in this
27:45:10
case uh we would not have any good oranges. So we can simply say that we did not had we did not find any good
27:45:16
oranges. So we can return the minutes. If we do find some good oranges then we need to return minus one. That's it.
27:45:23
This is the whole problem and this is the whole solution. Now I know that we can use Q plus we can use recursion to
27:45:30
complete the BFS call. Also for this given M crossN grid we are actually treating it as an adjacency matrix for
27:45:38
our graph kind of problem. And every single node we are treating it uh every single node that contains the value of
27:45:44
either a bad orange or an orange as a node and connection or the neighbors of
27:45:50
each other are being treated as sort of like edge between them. If we see time and space complexity in this case time
27:45:56
complexity is going to be simply big of V multiplied by E vertices multiplied by edges and for the space complexity well
27:46:03
since we are not using much space except storing a Q the space complexity would
27:46:09
be directly dependent on the number of bad oranges or number of total oranges present because in the worst case we
27:46:15
might have all the oranges that might go rotten. So this is the whole time and space complexity. Now let's quickly see
27:46:21
the coding solution. So my solution would make much more sense over there. So the very first thing we are doing is
27:46:27
to check that if the given grid is equal to null, we can simply return minus one. If that is not the case, we are going to
27:46:34
define the values of m and end. Then we are going to initialize a count called fresh count. This is to store the fresh
27:46:42
oranges that we have at the beginning of the cube. Uh and then we are going to start our cube where we are going to be
27:46:48
storing all the rotten oranges that we found so far. Now the first thing is count the fresh oranges and we are also
27:46:55
going to push down all the rotten oranges down to the skew. So we simply use two for loops to iterate over all
27:47:02
the values and we are going to be counting that what are all the fresh oranges we found and if we identified
27:47:09
that the value is two which means that particular cell position is a position of a rotten or orange. Okay so now
27:47:16
that's good. Now the very first thing we are going to check is for the edge edge case that if there are no fresh oranges
27:47:22
we can simply return zero that during the zero minute all the oranges are rotten. If that is not the case we are
27:47:28
going to initialize a variable called minutes with the starting position zero and we are going to have direction uh
27:47:37
array to iterate over all four neighboring directions for any particular cell. So these are not
27:47:43
nothing special just the zero and one combinations of adjacent cells and that
27:47:48
we can simply add to the current I and J positions. Now we start our BFS operation where we first check that if
27:47:55
the given Q we are going to iterate until the given Q is not empty. First thing we are going to check is the size
27:48:02
of the given Q. Then we are going to check that for any particular given I
27:48:08
position while it is less than the size of the cube. We are going to first of all pop one element out marking it as
27:48:15
rotten and then we are going to be iterating in all four directions. So notice that with the by by using the
27:48:21
direction variable we are actually going to calculate the x and y positions of all the adjacent cells. Then we we check
27:48:28
that are we going out of bounds. If we are not going out of bounds, then we are going to be turning the fresh oranges
27:48:35
into the rotten and we are going to reduce we are going to be reducing the count of the fresh oranges that we found
27:48:42
so far. On top of it, we are also going to be updating the um rotten Q and
27:48:49
adding those values inside our queue as well. Lastly, we are going to be updating the minute variable for every
27:48:55
single new breath first search operation that we make because this is the increment timer for every single level
27:49:01
of BFS. Now, in the end, we simply have to check that if the given fresh count is equal to zero, we are going to return
27:49:07
minutes. If that is not the case, we are going to be returning minus one. That's it. Now, let's try to run this code.
27:49:16
Seems like our solution is working as expected. Let's submit this code.
27:49:22
And our code runs extremely fast and it beats 99.99%
27:49:28
of every single solution which is pretty great, pretty awesome. Once again, you can see the coding solution on our
27:49:34
GitHub repository. So feel free to go ahead and check it out. Thank you.
27:49:49
So the lead code problem we are going to solve now is called walls and gates. We can see that this uh UI looks slightly
27:49:55
bit different than t our typical lead code problems and that is because this is actually a very popular lead code
27:50:02
premium problem. So that's why I took this uh screenshot from a website called leadcode.ca. So whoever is operating
27:50:09
that thank you so much. Now let's understand the problem statement. We are given an M crossN 2D grid that is
27:50:16
initialized with three possible values. First possible value is minus1. So minus1 defines that there is a wall or
27:50:24
an obstacle that we cannot cross over. Next value is zero. Zero defines that there is a gate. And third value is an
27:50:31
INF. So INF is a very large number basically. And if we are given this very
27:50:37
large number that defines that the given room is empty. So basically we are given
27:50:42
three distinct values. One value defines that on that particular cell position
27:50:48
there could be a wall or it could be a gate or it could be an empty room. So
27:50:54
for the rest of this problem let's just try to use only these three values. So it would make sense for us to
27:51:00
understand. Okay. Now we need to fill each empty room. So each cell that
27:51:06
contains the value E with the distance to its nearest gate. So this is the gate
27:51:12
that we are given. We need to calculate the distance from every single empty room to its subsequent nearest gate. And
27:51:19
if it is impossible to reach a gate, then it should be filled with an infinite value or which means like an
27:51:25
empty room. So let's try to understand this with an example. Basically we are going to be given a grid like this that
27:51:31
contains three different values uh infinity minus1 and zero. But the thing is I have presented them slightly nicely
27:51:39
over here. So let's try to understand and figure out that what does this problem statement is actually asking us
27:51:45
to solve. So we can see that there are bunch of different empty rooms that are
27:51:50
currently given to us and we are only given two different gates that these empty rooms can try to reach to. Plus
27:51:59
for some empty rooms we actually have walls that are coming in between. So we will have to ignore those walls and try
27:52:05
to figure out that what is the best way to reach to those particular gates. So let's just create an empty uh like empty
27:52:14
m cross grid and we will try to fill out these values. So we can see that for this very first position this one is an
27:52:21
empty room. So what are the closest gate to this empty room? One closest gate is
27:52:26
located over here. If we calculate the distance, this is actually three cells away. So in this case, one option is
27:52:34
that we can fill value three over here. Or if we have to calculate the distance between second gate, it looks like this
27:52:39
is very close. This see feels like that this is only two steps away. But that is not the real case. Why? Because there is
27:52:46
a wall in between. So we cannot cross the wall. So if we have to reach to this particular gate, we will have to go down
27:52:52
this path and then this path and then this path. So that actually makes the total distance as four. But the thing is
27:52:58
we need to calculate the shortest distance. So over here shortest distance to the gate is going to be value number
27:53:03
three. Same way shortest distance over here is actually going to be this gate that is this value number two. Shortest
27:53:09
distance over here is once again this gate and that is this value number one. Now this value is already gate. So we
27:53:16
can define it as zero or let me just mark it as gate for our understanding.
27:53:21
Now at this particular position the closest gate is actually this one and this is only two steps away. So we can
27:53:28
actually mark value two over here. Same way this is only one step away through this gate. Same way this is also one
27:53:34
step away through this gate. Same way this is two and this is three and this one is actually four steps away from the
27:53:40
gate and that path is actually going to be this one. So this is going to be four. For all the other ones the walls
27:53:47
are always going to remain the walls. So we can simply mark the walls as it is and the gate is going to be as as gate
27:53:54
and this is what we need to return as part of the answer. Uh now for some reason let's try to understand that
27:54:00
suppose uh this value is also a wall. Let's say uh that over here uh let's say
27:54:06
that this value is also a wall. Okay just for the understanding purpose. So then now at this position we have no way
27:54:13
to reach to a gate because both adjacent doors contains a wall. So in this case we are still going to make uh put this
27:54:19
as an infinite value or mark it as an empty cell. So just for our understandings okay so let's break down
27:54:27
the problem in subtask and we will try to calculate the result. Number one
27:54:32
thing we need to check is that distance of any particular cell from the gate.
27:54:37
This is the number one thing. Second condition we have is that if there is a wall we cannot cross. So we cannot go to
27:54:44
the wall. we do we should not consider if there is an empty room we will try to find that how many steps it take from
27:54:51
empty room to reach to the gate or from gate to reach to the empty room so now what the approach I'm suggesting is that
27:54:58
if we try to calculate at every single gate that or sorry every single empty room that where is the closest gate and
27:55:05
if we try to find this one this problem can get like slightly more expensive why
27:55:11
because remember that this gate location we will have to do like either a BFS
27:55:16
operation or a DFS operation. And we need to keep on iterating over of every
27:55:22
single possible neighbors in order to calculate that where does the nearest uh
27:55:27
nearest gate lies and it could take potentially big of like m cross n* for
27:55:35
every single grid in order to find both the gates in the worst case scenario. So
27:55:40
this problem can become like m cross n multiplied by m cross n that is going to be very expensive problem. So rather
27:55:47
than finding out the from like distance from empty room and searching for the
27:55:53
gates, it would make much more sense that from any particular gate, we can
27:55:58
start iterating over and branching out in like uh different traversal fashion
27:56:03
and try to find the empty rooms. And for each traversal that we make, we simply
27:56:10
have to do one iteration because uh we know that it is one step further from
27:56:16
the gate in order to reach to that particular empty room. So what the approach I'm suggesting is that first of
27:56:23
all we simply iterate over the given input array and try or sorry given input matrix and try to mark all the positions
27:56:30
that contains gate. We identified that this contains gate. Now from this gate we start traversing in all the possible
27:56:38
directions until we exhaust every single possibility of finding an empty room for
27:56:43
the from any particular gate. That is option that is number one thing. Second thing is that we also take care or take
27:56:51
into the consideration that if I have to reach to any particular uh any
27:56:57
particular empty room how many hops did I had to take in order to reach to that empty room. Also it could be possible
27:57:03
that some other gate can also reach to same particular empty room. Then we will try to put the value that contains like
27:57:11
the lower value compared to the current value we have as part of the empty room. So let me explain the solution then it
27:57:17
would make sense. Now the question is let's say that we identify that these two are the gate positions. We know where we are we want to iterate from.
27:57:24
But the question is how we are we going to iterate. Are we going to use depth first search or breath first search? So
27:57:31
logic is quite straightforward since in this case we will have to calculate how many hops it take to reach to any
27:57:38
particular location. We don't want to do the backtrack and keep on going in just one direction. We actually wants to
27:57:43
branch out in each of the directions. So logically it would make more sense to use breath for search in order to
27:57:50
calculate our result. So if we have to use breath for search we will actually have to use a cube in order to generate
27:57:56
the result. So idea is we are going to initialize a cube. In the queue, we are going to mark all the positions that
27:58:02
contains the current gate values. Then we from this particular gate value, we will keep on iterating over until the
27:58:08
next element. And all of its neighbors that we are able to reach that are currently empty rooms, we would mark
27:58:14
them to the gate as well. And we would try to update the value of those empty rooms by one plus. And the moment we do
27:58:21
the next iteration, we will add one more value. The moment we do the next iteration, we will do one more value. So let's say that we start our iteration
27:58:28
from this value. So currently this one is a gate. Okay, these are all the walls that we cannot use or we cannot go go
27:58:35
over. So let's try to start populating our array using this gate value and see
27:58:41
that how is the result we get. During the first iteration we are going to go down this path. So we know that for both
27:58:47
of them the distance is going to be 1 one and currently remember the distance is infinite. So we are always trying to
27:58:53
put the smaller distance on the place of the gate. Next is uh next from here we
27:59:00
cannot go anywhere because this is a wall. We already visited this node and uh so there are no other ways to go. But
27:59:07
from here we still have two ways to go down. So let's mark the values for both of them. So this is going to be two.
27:59:13
This is going to be two. Once again from this two we have one more way to go. So this is going to be three. And from
27:59:20
three we have one more way to go. This is going to be four. That's it. We exhausted all the possibilities down this path. But over here, we still have
27:59:27
more paths that we haven't traverse over. So this is going to be three. Then this is going to be four. This is also
27:59:32
going to be four. Then this is going to be five. So or sorry no this has to be a
27:59:37
gate value. So we are not going to do anything. So now we exhausted all the possibility as at this gate. Once again
27:59:43
we are going to repeat the same prog process from this gate and try to fill in the lower value. So if we branch out
27:59:50
this value actually becomes one because this value is and one is less than four. So we are going to put one over here.
27:59:56
Then this value becomes two because two is less than the current value we have. So this becomes two. Then this value
28:00:02
becomes three because this value is actually smaller than this one. So we can mark this as three. Now from this
28:00:09
two if we have to go this way this becomes three. But we already have a two which is already a smaller value. So it
28:00:14
makes no sense for us to go down this path. from this three we cannot go anywhere else. So that's it. Now this
28:00:20
state actually contains every single possible like distance of empty room to
28:00:27
the gate that we have been able to identify it and all we had to do is was to use a breath for search starting at
28:00:33
the gate and keeping track of all the graph related principle. So basically keeping track of all the visited nodes
28:00:40
and updating the value from the current position or every single new BFS we make
28:00:46
we simply have to add value by one and then we need to branch out in all four directions where the given gate is uh
28:00:54
sorry the given cell value is not a gate and it's not a wall which means any
28:01:00
place that is an empty room we need to calculate that what is the distance from a gate and if we do this for all the
28:01:06
gates eventually we would left with what is desired from us that we can return. So if we have to understand the time and
28:01:12
space complexity in this case the time complexity is going to be big of multiplied by n but we will have to do
28:01:19
this by the number of gates that are present and if we see space complexity well we will have to use a q in order to
28:01:26
do that and q depends on the number of elements. So it is also going to be big of multiplied by n and this is what we
28:01:33
need to return. This is a pretty good time in space complexity and congratulations you just learned an
28:01:38
awesome lead code problem. Uh that is a premium problem and you don't didn't have to pay for the lead code premium.
28:01:44
So anyways now let's quickly see the coding solution. So this is going to be the solution and uh I cannot run this in
28:01:52
lead code because this is a premium problem but I would still paste the solution in our GitHub repository so you
28:01:58
can check it out from there. So we have our infinite marked as a very large number. Then we are creating a static
28:02:05
position called direction to iterate over all four directions. Basically this will help us during our breath for
28:02:12
search calls. Now this one is the main method the walls and gate method where we are given the rooms as part of the
28:02:18
input. We first check for an edge case that if the given rooms are null we can return. If that is not the case we
28:02:24
define the values of M and N. Then we also initialize a new Q which we are going to use to do a breath first
28:02:30
search. Then we are going to find all the gates that are currently present inside our given array by using two for
28:02:37
loops and we are checking for the value that is equal to zero. After that we are simply going to do a BFS for every
28:02:45
single gate where we are checking that uh for this particular gate position
28:02:51
what are all the four directions that we can explore into. For each of the four directions we are going to check that
28:02:57
number one we are not going out of bounds and number two if the given value
28:03:03
of room that we are reaching toward the cell is actually infinite then we are simply going to update the value of the
28:03:09
distance and uh in the end we can simply add that value to our Q as well to keep
28:03:15
on updating the distance. So basically we are going to be storing like the smallest distance possible from every
28:03:21
single gate and this is what we need to return uh in the end. So this solution would work as expected and now let's uh
28:03:29
I won't be able to run it but you will be able to find the solution at my GitHub repository. So feel free to check
28:03:34
it out from there. Thank you.
28:03:47
So the lead code problem we are going to solve now is called surrounded regions. We can see that this one is a lead code medium problem and also very well-like
28:03:53
problem. Now the statement is quite straightforward that we are given an M crossN matrix named board that contains
28:04:00
bunch of different X's and bunch of different zeros. Now we need to capture all the regions that are four
28:04:07
directionally surrounded by X. And if a region is captured then we need to flip
28:04:14
all the zeros into that particular reg region into the axis that is a surrounded region. So let's try to
28:04:22
understand what they are trying to ask. We are given in this example uh an M
28:04:27
cross and board where we can see that there are bunch of different X values and bunch of different zero values. Now
28:04:32
in this case what is the definition of any particular zero surround zero region
28:04:37
to be surrounded? A region is surrounded if in all four directions it is uh
28:04:44
connected by some sort of X in each one of them. If that is the case, we can determine that this particular region is
28:04:51
surrounded. Now notice one important thing. We are not concerned with its
28:04:56
immediate neighbor. But even if the neighbor of the neighbor is still a value X, then we can determine that that
28:05:04
particular value is still surrounded by X's. So the moment we identify a
28:05:09
surrounded region all we need to do is convert all the zeros into x's which means we can see that this node is
28:05:17
surrounded by four x's in these four directions. Uh this part same way with
28:05:22
uh this particular zero it is surrounded by these four axis and same way for this particular zero it is surrounded by
28:05:29
these four x's. So logically all of these would be converted into the x's which we can see over here. But for this
28:05:37
particular region, it is only surrounded by X in three different directions, not
28:05:42
four. So we are not going to flip this zero into X. We are going to leave it as it is. And then we need to return this
28:05:49
state of the M crossN grid as part of the answer. So let's try to see that
28:05:55
what is the simplest logic we can use to solve this problem. Now let me give you
28:06:00
one example of bunch of different zero potential values in all of these
28:06:07
different grids. Let's say for this particular grid if we have any single value zero then that value has to be not
28:06:16
surrounded region. Why? Because currently this particular value is located over here. Even if in all all
28:06:23
the other directions we have access then also we would never be able to get a fourdirectional pattern where this
28:06:30
region becomes a surrounded region. So in the answer we are always going to have a scenario where this zero is going
28:06:37
to remain zero. Same way for this 3x3 grid. Let's say that if we have any
28:06:43
particular uh zero present over here and let's say that all the other values are currently x's. Then we can very easily
28:06:50
determine that this zero is actually surrounded by x's in all four directions. So in the answer when we try
28:06:56
to create basically this zero has to be flipped into x. That is true. But let's
28:07:02
say instead of doing that, instead of this being zero in this middle portion, let's say if we have zero located at any
28:07:09
of these edges, any of these. Okay, I'm not saying all of them are zeros. Let's
28:07:14
say any one of this is a Z uh zero. And let's say that all the other values are X's. So I'm currently marking these by
28:07:21
bunch of different X's. This region would never be surrounded. That's a given fact. Why it would never be
28:07:28
surrounded? because there is always going to be one or two directions where
28:07:33
it is located on the edge which means there can never be an X planted over here. So in if the node if the node is
28:07:42
in the middle then it has the possibility of being a surrounded region but if we identify zero at any
28:07:49
particular edge then that zero is always going to be a not surrounded region. So
28:07:55
it it does not needs to be changed. That is what I'm trying to explain. Now let's try to see one more example. In this
28:08:01
case, let's say if we have any particular these four zeros placed like this and all the other values are X's.
28:08:07
In this case, all of these zeros has to be converted into the AIS because all of this becomes a surrounded region. But
28:08:14
for some example, if we have any particular zero located over here, we already established that this does not
28:08:20
needs to be changed. That is number one thing. Second thing is that not only this does not needs to be changed. Let's
28:08:26
say that if there are any particular other zeros connected with this value then also they are also going to be not
28:08:34
surrounded regions. Once again I repeat, if there are any particular zeros that
28:08:40
are connected with this edge, then we can determine that this is also going to
28:08:45
be not a surrounded region. And we are going to exploit this property to its fullest because uh remember in this case
28:08:53
particular this zero is actually always going to have one more zero located over
28:08:59
here which means it can never be four directionally challenged by another zero. And this is what we are going to
28:09:05
use to solve this problem. Uh what we are simply going to do is that we are
28:09:10
going to treat this as a graph problem on not only a graph problem we are also
28:09:16
going to treat it as a graph traversal problem where we need to do the depth
28:09:21
for search at any given moment we identify a value that is currently zero. The thing is we are not just going to
28:09:27
blindly start looking for zeros in all of these particular grids that it makes
28:09:32
no sense. If there is any particular zero in the middle there it might be possible that there might be access in
28:09:38
all four directions that could prevent it from becoming a not surrounded region. What we are going to do is we
28:09:44
will try to only traverse into the edges of this particular matrix and for each
28:09:50
of the edges we will try to find that if there exist any particular zero then we
28:09:56
are going to start doing the DFS and all the values that we identified through this iteration. we are just going to
28:10:02
mark those numbers that they are always going to be four directionally not
28:10:08
surrounded regions and all the other regions or all the other values we can simply mark them by x. So let me let's
28:10:14
try to understand this with an example that I'm trying to show you. Let's say that in this case we are currently given
28:10:19
that this particular these two nodes are currently zeros and let's say that this is connected with this zero and let's
28:10:25
say that this one is not connected with anyone else and then we have this zero connected like this and all the other
28:10:31
values are currently x values. So logically the algorithm I'm proposing is
28:10:36
that we start iterating over this m cross n grid in first of all all the edges. So let's say that these four are
28:10:44
the edges and then we once again identify this edge and this edge and
28:10:49
then this edge and this edge. So we found a one edge that contains a value
28:10:54
zero. The moment we identify one edge that contains the value zero, first of all we are going to mark this one as a
28:11:00
special zero. So let's say that I'm keeping track of all the zeros that I have been able to identify so far. And
28:11:06
let's say that this one is a special character that contains a zero at the edge. Then we are going to do the DFS
28:11:13
operation in all four directions to find all the connected zeros. But we can see that this one does not have any
28:11:19
connected zeros. So we are just going to say that this is the only zero we find and then continue with our iteration.
28:11:25
Once again we are at this position. This is also X. Once again we identified one more zero. So the moment we identify one
28:11:31
more zero, we are going to mark it as a special character. And then we are going to start doing the DFS operation in all
28:11:38
four directions. This one is an X. So we don't do anything. This one is an X. So we don't do anything. But this one is
28:11:43
not an X. So this one is also a zero. And a zero that has been found by
28:11:50
reaching a zero that was present in the edge. So once again we are also going to mark this as a special character and
28:11:56
then uh now from now on we cannot move ahead anywhere forward. So we cannot do
28:12:01
anything. On top of it for our DFS operation we will have to keep track of all the visited nodes. So we are also
28:12:07
going to mark all the visited nodes as well. So it's just some simply for our convenience and that's it. So once again
28:12:14
we don't find any more access. So then we simply say that we iterated all the
28:12:20
edges we reach we did the DFS on whenever we found a zero at the edge and
28:12:26
uh we mark those nodes and apart from these nodes everything else should be
28:12:31
converted into the axis which means this node has to be converted into an x and
28:12:36
that's it. This is the state of m cross n that we need to return of all the
28:12:41
zeros that are not surrounded and all the surrounded regions are being converted into the x's. So that's it.
28:12:48
This is the whole solution. Uh if we try to understand the time and space complexity in this case, time complexity
28:12:53
is going to be big of m cross n because we will have to iterate over every single nodes. And this is an example of
28:12:59
ad adjacency matrix kind of representation for the graph. Space complexity. Well, this is de debatable.
28:13:06
If you have to create a new snapshot then you might have to use m cross n space. If you can modify this current
28:13:12
existing node just by changing this character from something else from zero maybe something like a hash or something
28:13:19
then also we can use the same pattern or same logic. So it's up to you how you
28:13:24
want to approach that or how your interviewer wants to do that. It can be a common space complexity or if you are
28:13:30
uh if you're not allowed to change the input then it it is going to be big of n cross n space complexity. So now let's
28:13:37
try to see the coding solution for this one. So the coding solution is quite straightforward. We need to solve the
28:13:44
given board and first we are going to check for the edge case that if the given board is equal to null we can
28:13:49
simply return. If that is not the case, we are going to define our m and our n.
28:13:55
Then we are going to start iterating over the boundary and start marking all
28:14:00
the zeros that we find on the boundary as like a temporary character or a temporary variable. So let's say that we
28:14:08
run two loops. We have this if condition that if the given node is equal to 0 or
28:14:13
m cross m minus one and j is equal to0 or n minus one. which means we are checking for the edge nodes. On top of
28:14:20
it, we are also checking that if the given board position marks the value as zero. If that is the case, then we are
28:14:27
going to call our DFS method. In the DFS method, we are checking that all the
28:14:32
surrounded regions that we need to find. So, this is our DFS method where we are
28:14:39
first of all checking that if the given node is equal to null or we exhausted all the possibilities, we can simply
28:14:44
return. If that is not the case, we are going to mark that particular value as a temporary character T stating that this
28:14:51
has been visited and we are going to run the DFS operation in all four directions.
28:14:57
Which means we are only going to be left with temporary values that are currently
28:15:03
visited by us after this DFS operation that are connected with the zeros that are located at the edge. Then uh once
28:15:10
that is done we simply need to check uh and capture all the surrounded regions. So for that we can simply iterate over
28:15:17
the given input array and check that if the given input board position is equal to zero which means it is not t then we
28:15:24
are going to simply mark it as x. If that is not the case and if that value is t which means it is not a surrounded
28:15:31
region. So we are going to mark it as zero. And that's it. This is the whole solution. Let's try to run this code.
28:15:41
Okay, seems like our solution is working as expected. Let's submit this code
28:15:48
and our code is exceptionally faster compared to all the all the other solutions which is great to see. And uh
28:15:54
once again you can find the solution on my GitHub repository link is in the description. Thank you.
28:16:07
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. Today we are going to do core schedule lead code
28:16:12
problem. And this is one of the most versatile problem uh that has been asked at bunch of different companies like
28:16:19
huge huge huge number of companies. Uh we can see the companies like Amazon, Microsoft, Facebook, Google, Tik Tok,
28:16:25
Snapchat, Robin Hood, Twill, Uber, eBay, Tesla. All the companies have
28:16:32
asked this question and this question is very practical real life application. So that's why a lot of companies like to
28:16:38
ask this question. So this is a lead code medium problem
28:16:44
and we are given a number of courses and we are also given an array of prerequisites where any single entity in
28:16:51
array is defined like this where where we are given two values suppose A and B
28:16:56
separated by a comma which means that we must complete course B first in order
28:17:02
for us to complete course A. So suppose we are given an entity in the prerequisites like this one and zero
28:17:08
which indicates that this course one actually has a prerequisite called course zero. So we can define it like
28:17:14
this that course one as a prerequisite on course zero and uh in terms of the practical manners we first complete this
28:17:21
code course zero in order for us to complete this course one and based on
28:17:26
the information given we need to check that whether we can finish all the courses or not and if we can finish all
28:17:33
the courses depending on whatever the prerequisites we are given we need to return true otherwise we need to return
28:17:38
false. Okay, now that we understand the problem statement, let's take a custom example to understand the problem.
28:17:44
Suppose we are given the list of prerequisites like this
28:17:50
and we are given the number of courses as four which means that we need to
28:17:57
complete the 0 1 2 and 3. These four courses we need to complete and this is
28:18:03
the list of prerequisites we are given. Now we can consider this as actually graph problem. Uh we can consider these
28:18:11
as graph ed nodes and uh the prerequisite information we can treat them as graph edges. So over here we can
28:18:19
say let's plot it on a graph and let's see that how it would look. So over here
28:18:25
one has a dependence on zero. So I mentioned this 0 has a dependence on
28:18:32
three. So let's also mention this. and two has a dependence on zero. So two has
28:18:38
a dependence on zero. Okay. So this is how we can plot this on on a graph and
28:18:44
we need to see that whether we can complete all of these forces or four courses or not. So the most intuitive
28:18:50
solution is to check from the beginning. We check at this course number uh zero that can this course number zero be
28:18:56
completed or not. Now in order in order for us to complete this course number zero, we see that this course zero
28:19:03
actually has a uh edge pointing towards course number three which means that course three is a prerequisite for
28:19:09
course zero. So we need to complete this course three before we can course complete course zero. Now with we are at
28:19:15
this course three again we check the same thing that whether we can complete the course three or not. Now course three does not have any prerequisite
28:19:21
which means it can be completed on its own. So we say that okay course three can be completed. Now again we backtrack
28:19:28
to zero. At zero we check that do does zero have any other prerequisites that we need to take care of the no zero is
28:19:35
zero only has one prerequisite on course three which we can complete which means that we are able to complete course zero
28:19:41
as well. So we can mark this uh and the square box indicate that we are able to complete that course. So we are good. So
28:19:48
we already know that zero can be completed three can be completed. Now we check for this course number one. So at
28:19:54
course number one we check that what are the prerequisites for course number one. Well course number one has a prerequisite on course number zero. So
28:20:02
we since we already know that course zero can be completed which means we can uh also conclude that course one can
28:20:08
also be completed which mean which we can mention over here and we can check for this course number two. So course
28:20:14
number two also has a prerequisite on course zero which is already done which means we are able to complete course
28:20:19
number two as well. So in this case for all the four courses we are actually able to complete them and uh we can
28:20:27
return true in this case that yes uh based on the given uh number of courses
28:20:32
and prerequisites we are able to complete all the courses. Now
28:20:37
we need to check that what could be the scenario if we cannot complete the course. So suppose we are given an
28:20:44
additional edge like this in the same example.
28:20:52
Suppose we are given this additional edge. Now let's see that how the dynamic would change. Let me clean this up a bit.
28:21:01
Okay. Now we have this additional edge 32 which means that in order for us to complete this course number three we
28:21:06
would need to complete course number two as well. Now let's see that can we complete. So initially we would check
28:21:12
that can we complete this course zero. So in order for us to complete course zero we would need to complete course
28:21:17
three. Okay. Now in order for us to complete course three we would need to complete course two. Okay. And again in
28:21:23
order for us to complete this course two we would have to complete this course zero. So notice that we are constantly
28:21:29
stuck inside a loop. It's the same scenario where you need experience to gain a job and you need a job to gain
28:21:34
experience. Uh it's some somewhat similar kind of example that we are stuck inside the loop which means that
28:21:40
no matter what happens we are not able to complete any of these three courses without completing the other one because
28:21:47
there is an interdependence between each other and uh essentially in this case we
28:21:52
would have to return false that we cannot complete all the courses. But the
28:21:58
thing is why do why did we have to return this false? Well the only the reason is quite simple. Basically we in
28:22:05
terms of graph manner if we speak what was the difference from this graph compared to this previous graph only
28:22:11
this edge and when we added this edge what essentially we did was we introduced a loop inside our uh graph
28:22:20
amongst these three values 0 2 and 3. So we can conclude one thing that at any given moment if we've identified that
28:22:27
there exists a loop inside our graph we would be able to immediately return false. if there does not exist a loop
28:22:33
and we are able to from every single element we are able to complete all these prerequisites in the that scenario
28:22:38
we need to return true. So now we have these two information let's see that how can we use them and how can we solve
28:22:44
this. So suppose we are given an example like
28:22:50
this and uh these are all the prerequisites that we are given and we need to complete the six total six
28:22:55
number of courses uh in order for us to conclude that this graph can be uh scheduled or not. So essentially we are
28:23:02
going to apply the same logic. We are going to first of all take these inputs. We are going to convert them in a graph
28:23:08
like this. Uh inside the graph for every single course we are going to see that whether we can justify these
28:23:14
prerequisites or not. And uh at any moment if we identify that there exists a loop we will immediately terminate and
28:23:20
return false. If there does not exist a loop we would keep going and uh
28:23:25
eventually we would return true. So that is the idea and in order for us to achieve that first of all what we are
28:23:32
going to need is we are going to need some sort of graph data structure because initially the only only two
28:23:37
values we are given is number of courses and the set of prerequisites. Uh so first of all we would create a data
28:23:44
structure like uh hashmap and inside of our hashmap we are going to store two
28:23:49
values. we are going to store as a key we are going to store uh the number of courses and as a value we are going to
28:23:56
store the uh number of prerequisites that every single course has. So
28:24:01
initially we would have so this is the number of courses and these are the prerequisites that we
28:24:08
have uh and we would try to see that can we complete all the courses or not. So
28:24:14
first of all we are at the score zero. So in order for us to complete the score zero we need to see that what are the
28:24:19
prerequisites for course 0. Uh so for course 0 the prerequisites is course two. Now for this course two what is the
28:24:26
prerequisite? The prerequisite is actually course three. Okay. And now for this course three the prerequisite is
28:24:32
actually course four. So here and the for this particular course four the prerequisite is actually course five. So
28:24:39
here now we are at this course five. We check that can we complete this course for five five and yes we are able to
28:24:46
complete the course five because it it there exists an empty list. So which means we can conclude that course five
28:24:51
can be completed over here because there is an empty list. So again we backtrack we go back to course four. At this
28:24:57
course four we know that course five can be completed. Since course five can be completed. We can also have an empty
28:25:03
list over here because it defines that at any moment if we are at this course four that course four can always be
28:25:09
completed because its prerequisites are already met. So we can have an empty list over here. Now again we go back. If
28:25:17
we go back we are at the course three. So in order for us to complete the course three we would need to set up an empty list over here because course four
28:25:23
can be completed. U that is done. Now again we come back to the course two. At
28:25:29
this course two again we will create an empty list and now uh we are at this
28:25:36
course zero. So at this course zero we only have a dependence on course number
28:25:41
two. So we can also have a an empty list over here basically defining that course
28:25:46
zero can be completed. Okay. So that is one observation that has been done. Well now and see that we were only trying to
28:25:54
calculate that can we complete this course four but we already concluded that we can complete these all these
28:25:59
courses as well and we have already established them inside our hashmap. So
28:26:05
at any moment uh we only need to identify the remaining courses and not all of these courses that we have solved
28:26:11
already which means we are efficiently improving our solution. Uh second we come at course one. Now this course one
28:26:18
actually has three dependencies. uh course two, course four and course five. So let's take care of uh each of them
28:26:25
one by one. First of all, we will check that from course one can we complete course two. So we check for this course
28:26:30
two and we check that the these prerequisites are already met because there exist an empty list which means
28:26:35
that we can eliminate course two from over here from the list of prerequisites because we know it can be completed.
28:26:41
Again we check the same thing for the course four. Uh over here the scores four we again have the empty list. So we
28:26:47
can also eliminate the course four over here as well. And again we can repeat the same process for this course five
28:26:52
that course five can also be completed because there exist an empty list which means even at this position course one
28:26:58
we can create an empty list over here. And now if we look at all the courses
28:27:04
the only prerequisites we have are just empty lists and uh once we achieve that basically we
28:27:11
can conclude that we have already reached our solution and we can return true in this case. So this solution
28:27:17
works perfectly fine. But the thing is we missed the key point over here. Like because this was a true scenario, we did
28:27:23
not identified any issues. But the thing is if there was an a loop, we were not actually checking that whether we are
28:27:30
encountering any loop or not. So let's see that if we want to encounter any loop at any iteration, what would be the
28:27:36
additional steps we need to take? So let's modify our example a bit.
28:27:45
Suppose we have an additional prerequisite like this 53 that in order for us to complete this uh course 5 we
28:27:52
will need to complete course three. So we will have an edge like this and uh let's modify our prerequisites table.
28:28:03
Okay. Now in this example we know that there exists a loop between this uh three four and five. So we need to take
28:28:11
care of it and in order to take care of it I'm suggesting that we create an additional hash set uh at the beginning
28:28:18
of uh checking for any single course. So we create a hash set
28:28:27
and in the in our head we just name it as visited or something and over here we
28:28:33
will keep track at that at any location are we repeating the same element. So
28:28:38
let me show you what I mean by that. So initially suppose that we are at this course 0 and then we start our program.
28:28:46
So we want to check that whether we can complete course 0 or not. So first of all we are we will check that whether we have already visited this core zero in
28:28:52
this current iteration. So we check in this visited node that have we visited core zero and because it's a hash set
28:28:59
it's a constant time operation. So we are not adding any additional strain on the time complexity. So we haven't
28:29:06
visited this node zero. we would uh so we would add an entry over here first. Now we will check over here that what
28:29:13
are the prerequisites for this course zero. So the prerequisite is course 2. So again we would add we would check our
28:29:20
visited node first. So course 2 is not part of it. So we would add an entry over here and uh again we would continue
28:29:27
over here. So now we need to check this course three. Again we would add it entry to the visited node. Uh we check
28:29:34
over here we need to check course four. Four we haven't visited. So we would add an entry over here. Uh then we would
28:29:40
check the four's prerequisite. Uh five five we haven't visited. So which means
28:29:45
we would add an entry over here. And now at this five we would check the prerequisite for five. So for the
28:29:51
prerequisite for five is actually three. So we are again at this position three. So first of all we will check that
28:29:57
whether we have visited this three or not. And this time we would know that yes we have already visited this node
28:30:03
three. uh which means that we are in a loop. So this is what this hash set uh
28:30:10
confirms and the moment we find out we can immediately return false over here. we don't even need to check any
28:30:16
additional uh items in this given uh graph and uh we would be able to
28:30:22
terminate our case immediately which means and in case if this edge was not existent uh this entry for this value
28:30:30
number five for this value number five we wouldn't have to check anything and uh we would
28:30:36
have been able to complete all our code and uh we would have been able to return true but which is not the case this time
28:30:42
because there exists an additional prerequisite as specified over here. So
28:30:48
this would be our final solution. And now let's calculate the time and space complexity for this one.
28:30:54
So for time complexity we can actually complete this whole thing in big go of v
28:31:00
+ e time because at any moment the maximum traversal we will have to do is
28:31:06
from one uh one node to all the single uh nodes and uh throughout all the
28:31:12
single edges. So this would be the time complexity and space complexity because we are creating an additional uh data
28:31:20
structure like this hashmap and also this hash set. But the thing is hash set is going to be smaller. So we are only concerned with this hashmap. For general
28:31:26
time complexity it would be uh sorry space complexity it would be big of v plus e as well and
28:31:36
okay first of all we will create a hashmap and we are going to store uh integer and
28:31:43
list inside it. We will name it course graph.
28:31:50
Okay. Now we will have to build our graph. So essentially we are going to iterate over every single uh
28:31:56
prerequisite in the given prerequisites
28:32:02
and first of all we will check that whether this prerequisite is already added in our graph or not. So
28:32:12
if it is added already we only need to append the new prerequisite.
28:32:21
And if it does not exist, we will need to create a new one. Uh we'll have to
28:32:27
create a new entry in our course graph.
28:32:32
So we will create a new list and add the list. And then we will add the entry of the course and uh the list to our graph.
28:32:43
Okay. So after this loop ends, uh we should have our graph structure ready. So now we will create a hash set uh that
28:32:51
will take care of integer values and we'll name it visited.
28:32:59
And now we will have to run a loop for all the courses that we are given.
28:33:05
And now we will have to create a method to check that whether there exist a cycle inside the loop or not. And uh
28:33:12
let's name our method that uh course schedule
28:33:17
which indicates that whether we can schedule a course or not. In this course schedule method we are going to provide
28:33:25
the current uh course the visited node
28:33:34
and the graph that we had created.
28:33:41
And if this response back to false at any given moment, we
28:33:46
would know that we cannot create the core schedule. So we will return false immediately.
28:33:54
And if this loop ends and we don't return false, which means that everything was successful and we we can
28:34:00
return true. Okay. Now we will have to create this core schedule method. So let's create a
28:34:07
boolean method. Now let's uh test our terminating cases.
28:34:13
So if our set contains the current course
28:34:19
which means that we have detected a cycle so we can terminate immediately. So we can return false.
28:34:27
Uh also we check that if for the current course uh we if we already have an entry
28:34:33
in the graph where it has an empty array list we can return true.
28:34:41
If that is not the case we will have to iterate over all the prerequisites for any particular uh course. So first of
28:34:47
all we will add the current course that we are iterating over in our visited hashet.
28:34:57
then we will iterate over every single prerequisite for that particular course
28:35:06
uh we would uh we would call our recursive function. So
28:35:15
and we will provide the current we will provide the current prerequisite we are
28:35:21
at we will provide the visited uh hashet and we will provide the graph
28:35:30
and if at any point this returns false we can return false immediately.
28:35:40
However, if this uh loop executes, we know that for that particular course, we
28:35:45
are actually able to complete uh complete the course and we can schedule it. So, first of all, we will remove it
28:35:50
from the visited node
28:35:56
and then now since we know that uh this particular course can be completed, we would update the entry for that course
28:36:02
in our course graph. Uh so
28:36:11
we would set uh the prerequisite to null.
28:36:19
Which means that in future at any point if we identified this particular course
28:36:24
we know that we are able to complete it and we can just move forward quickly and uh at the end we can simply return
28:36:31
true in this case. So I guess this would be our core
28:36:37
schedule function uh where the main logic happens and uh let's try to run
28:36:42
the code. Okay, seems like our code is working. Let's try to submit the code.
28:36:49
Okay, our solution works and uh it's it works pretty efficiently. So I would be
28:36:54
putting this solution in the uh comments. You can check it out from there. And this was a really long video.
28:37:00
It took me a lot of time to make it. So, I hope you like it and let me know in the comments on what are your thoughts
28:37:06
about this problem. Um, see you next time.
28:37:19
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to become
28:37:24
better at technical interviews. Keeping with that goal in mind, today we are going to solve a very important lead code problem. So, let's get started with
28:37:31
the problem. So today we are going to do core schedule 2 lead code problem. And if we see some of the popular companies
28:37:36
who have already asked this question there are companies like Amazon, Google, Microsoft, Tik Tok, Apple, Plentier,
28:37:41
Bite Dance, Roblox, Uber, Facebook, Robin Hood, Snapchat, Bloomberg, Door Dash, Lyft and Goldman Sachs. So this
28:37:49
has been a very popular question at many different companies. I'm going to pay my utmost attention. I hope you also enjoy
28:37:54
the video. So this is a lead code medium problem
28:38:00
and also very well-like problem on lead code. In this case we are given two items. First item is number of courses.
28:38:06
Now the number of courses it says that suppose we are given number of courses to be three. Which means that we are
28:38:11
given the courses 0 1 and two. Suppose we are given the number of courses to be five. In this case the number the
28:38:18
courses are 0 1 2 3 and four. So this is what the number of courses defined.
28:38:23
Second item we are given which is more important is the array of prerequisites.
28:38:28
Now what does an array of prerequisites defined? Well, there can be a structure that looks like this A B. What this
28:38:36
means is that uh course B is a prerequisite for course A. We all know
28:38:41
that we need to complete like the prerequisite course in order to go and do the more advanced level courses. So
28:38:48
in this case if we complete course B then we are eligible to complete course A. But say for example for some reason
28:38:55
we are not able to complete course B we are guaranteed that we would never be able to take part in or be eligible to
28:39:02
complete course A. Now after having these two items number of courses and prerequisites uh basically what we need
28:39:09
to do is we need to return an ordering of courses such that we are able to
28:39:14
finish all the courses and what does finishing all the courses means that we are abiding by the list set of or the
28:39:21
all the prerequisites that we are given amongst all the courses and uh
28:39:27
definitely there could be many different answers to that uh we can complete the courses in many different ways. So we
28:39:32
need to return any of the valid answer and some for some reason if we are not able to complete all the courses we need
28:39:38
to return an empty array. So let's try to understand this with few examples. So in the first example we are only dealing
28:39:44
with two courses. So the two courses are going to be zero and one. Now for these two courses we are only given one
28:39:50
prerequisite and this prerequisite says that course zero has to be done in order to be eligible to complete course one.
28:39:57
So if we complete the courses in the ordering of 0 and 1 then this is going to be a legitimate answer where we are
28:40:04
first we complete the course zero because it has no prerequisites and since we have already completed course
28:40:09
zero we are eligible to complete course one and this is going to be a valid answer. So we can return this as the
28:40:15
answer. If we take the second example this is little bit more complicated. Now we are dealing with four courses which
28:40:20
means courses are 0 1 2 and three. Now in this case if we see there are bunch of different prerequisites. So let's go
28:40:26
every single one of them and try to uh find some answer. So first one it says
28:40:31
that course zero has to be done before we can do course one. Okay that that is good. Second one says that course one
28:40:37
needs to be completed before we are eligible to do course two. So we have already completed course one over here.
28:40:42
So let's try to do course two after that. Then it says that course two has to be done before we are eligible to do
28:40:48
course three. So over here we are already done with course two. So let's complete course three after that. So this is one of the valid orderings and
28:40:56
in this case if we return 0 1 2 and 3 as the answer this is going to be a perfectly valid answer. Uh and in this
28:41:02
manner we are keeping track of all the prerequisites and we are also completing all the courses. Let's take one final
28:41:08
example. So if we see in this final example this is a little bit different example. So over here we are given three
28:41:14
courses. So courses are going to be 0 1 and two. Now we are given some prerequisites. So let's try to go
28:41:20
through each one of them. So first one is 0 to 1. Okay, we need to complete course zero in order to complete course one. That's good. Now second one, it
28:41:27
says that we need to complete course one in order to complete course two. So one we have completed over here. Let's
28:41:32
create uh it for two. But now this prerequisites it it's a little bit
28:41:37
tricky and the tricky part is that we need to complete course two in order to complete course zero which is the tricky
28:41:44
part because now if we see there is no way for us to complete like all three
28:41:49
courses because every single time we are going to be bounded by some other course
28:41:54
because definitely in order to complete course one we need to complete course zero. In order to complete course zero we need to complete course two. In order
28:42:01
to complete course two we need to again complete course one. But we cannot complete course one because zero hasn't been done. So this is going to be keep
28:42:08
running in the round and round and this is a huge problem. So in this case we are simply going to return an empty
28:42:13
array because we cannot find an ordering that satisfy all the properties.
28:42:20
So based on my drawings and all the logic I'm trying to show you it's it
28:42:25
becomes pretty trivial that how we are going to solve this problem. Uh the way we are going to solve this problem is using graph theory. And for the graph we
28:42:33
need two items. We need nodes and we need edges. So as the nodes we are
28:42:38
actually going to use the number of courses that all the courses are going to represent a node in itself. And for
28:42:45
the edges we are going to take all the values that are present inside the prerequisite table and based on that we
28:42:52
are actually going to create an edge and that is going to give us very interesting results. Now in this case
28:42:59
say for an example if just consider this example and let's try to draw a graph in this case. So first one okay we are
28:43:06
given four courses. So we are going to draw four nodes. So first prerequisite
28:43:12
is that we need to complete course zero in order to complete course one which means 0 is actually a prerequisite for
28:43:18
course one. So we can have an edge between 0 and one where 0 is a prerequisite and one is the node that we
28:43:26
that needs the prerequisite of zero. So notice in this case I'm only drawing one directional edge. Why? Because for one
28:43:34
zero is a prerequisite. So that's why there is an edge between 0 to one. But the thing is for zero there is no edge
28:43:40
coming back from one because so far we haven't find that there is a prerequisite in this case. So because it
28:43:46
is not the case we are simply going to keep progressing. Now next one is that we need to complete course two in order
28:43:53
to complete course one. Right? So basically from 1 to two there is also going to be an edge because uh course
28:44:00
one is a prerequisite of course two and course one has to be done before we can proceed to course two. So that is why
28:44:06
there is an edge from two to uh 1 to two. Same way we must do course two
28:44:11
before we can proceed to course three. So we must do course 2 in order to proceed to course three and this is also
28:44:18
a prerequisite and this is a graph that has been made based on the number of
28:44:25
courses and the area of prerequisites that we are given. Now our aim is to find any legitimate offering. So for in
28:44:32
order to find any legitimate offering the logic is going to be quite simple. What we are going to do is we are going to pick any single node and we are going
28:44:39
to do a depth first search. Now in the depth for search we will have to keep track of like two three items. First
28:44:46
thing we will have to keep track of is that there are no cycles. If we find cycle basically we have entered a
28:44:53
scenario where we are not able to complete all the prerequisites. Say for example in this case if we are given an
28:44:59
additional node that looks like this or sorry an additional edge that looks like this. So in this case we have actually
28:45:05
detected a cycle and because we have detected a cycle there is no way for us to complete all the courses. So
28:45:11
definitely in this case we will have to return an empty array. But lucky for us in this case we are not given a
28:45:17
prerequisite that looks like this right. So we don't we found no cycles. Second thing we need to do is we can pick any
28:45:23
single node and from that node if we start iterating over all the all of its neighbors in the DFS manner and then
28:45:31
keep a track of all the elements that we have visited uh by doing that we won't be able to find any cycles and also uh
28:45:38
we will try to order them in a manner that uh we match all the dependencies
28:45:44
and in the end we simply need to return the ordering. So this is going to be a perfect logic to solve this problem. Uh
28:45:50
that we are taking consideration of everything. Now let's see that we know the core logic that how we are going to
28:45:56
use it. Let's see how we are going to implement it.
28:46:02
So in this case we have total seven courses that we need to take care of. And for all of these seven courses I
28:46:08
also have a prerequisite array. Now based on these two things we know that
28:46:13
for any single graph problem we need to rep we need a way to represent the
28:46:19
entire problem in a graph manner. So how we can do it is we we have two ways we
28:46:24
have adjacency list and adjacy matrix right. So in this case I think we are
28:46:31
good with going with adjacency list rather than adjacency matrix because the
28:46:36
graph is not going to be too sparse and uh so let's try to keep stick with adjacency list. Now based on this given
28:46:43
array we would be able to create our adjacency list. Now how we are going to create our adjacency list? Well
28:46:48
basically for adjacency list we are going to create a hashmap. Now inside this hashmap we will have to take care
28:46:55
of two values. First one is like the key and second one is its value. So as a key
28:47:01
we are going to take all the courses that are present and as the value we are going to take that which courses like
28:47:09
for that particular node for home it is the prerequisite
28:47:15
again I'm repeating myself. So as the node we are going to take all the courses. So basically the nodes are
28:47:22
going to be 0 1 2 3 4 5 6 7 over here and as its value we are going to see
28:47:28
that for what are all the courses it is a prerequisite for. So let's try to draw
28:47:34
our graph and also fill up our prerequisite uh table. Okay. So based on
28:47:40
the given prerequisites we have been able to draw our graph. Now if we see on the graph uh graph is only for our
28:47:47
explanation. Basically all we will have to do is we will have to create our prerequisite uh adjacy list that I
28:47:53
mentioned. Now in the hashmap these are all the nodes or the number of courses as mentioned and now let's uh try to
28:48:00
keep on mentioning their prerequisites. So first we will see that what for what are the courses zero is a prerequisite.
28:48:07
So from the graph we can actually take a look at this prerequisite array as well. Well thing is I feel it would be better
28:48:12
if we just do it from the graph. It would be easier to visualize. So in this case basically course one and course two
28:48:19
these are the two uh neighbors or these are the two edges that derive from
28:48:24
course zero which means uh unless completing course zero we cannot complete course two or course one
28:48:30
because for both the courses zero is a prerequisite same goes okay let's see for course one course one is actually a
28:48:36
prerequisite for course number six okay that's cool for course two okay course two is a prerequisite for course number
28:48:42
four and six actually has no prerequisites Okay, now we have done
28:48:47
half of the work. We have created our graph. Now the question is how we are going to traverse the graph, how we are
28:48:55
going to make sure that we are finding cycles and how we are going to keep track of all the answers that what
28:49:01
should be the correct ordering. So these are the three tasks we will have to do. The traversing part is pretty easy to
28:49:07
solve. We are simply going to use the DFS and we will keep on iterating. The question is how we are going to detect
28:49:13
cycles whether they exist or not. In order to do it basically from any single
28:49:18
node if we are going to do a DFS we will have to keep track of that at any given
28:49:23
position we are not coming back to that particular node that from where we started. So we will have to find a way
28:49:30
to keep track of all the visited nodes. So one of the best way to keep track of visited node is using hash set. So we
28:49:37
are going to use couple of hashets. There is also another trick where we can give the nodes some numbers and uh or
28:49:45
some colors where we can treat them as such that whether they have been visited or not. But for explanation purposes,
28:49:51
let's just keep track of hashet. When we go to the coding, we are going to use it differently. Now, we also need to keep
28:49:57
track of the ordering. The idea we are going to use over here is that we are actually going to use a stack. Initially
28:50:04
the stack is going to be empty and from whatever the node we started visiting we
28:50:10
will keep on visiting until we reach to a point where it does not have any prerequisites or all the prerequisites
28:50:17
has been met. Once we get to that point we would add that course into our stack.
28:50:22
Eventually our stack is going to be full. And remember the idea of a stack is that in the stack we keep on adding
28:50:29
adding adding all the values. when we pop off we pop off all the values in the reverse manner then we added so
28:50:35
basically we are adding the first value inside that contains basically all the
28:50:40
prerequisites and then we will keep on adding values on top of it so the top
28:50:46
value inside our stack is going to be a value that contains no prerequisites and
28:50:51
uh then we will keep on popping one value at a time and in the end we should be able to get our answer. So after this
28:50:58
long explanation, let's see all of these things in action. Okay. So now we have our structure ready. Uh I have created
28:51:05
an adjacy list over here. Now for this adjacency list, first of all, we are going to do DFS. So I'm going to keep
28:51:11
track of that what element we are dfsing over. We are for any single DFS that we
28:51:17
are doing, we will also have to keep track of the current visited nodes that we are going through because during the
28:51:24
DFS we do not want to find any cycles. So if any element appears in the
28:51:29
currently visited elements during the same DFS, we would know that we have encountered a cycle. Right? Suppose we
28:51:34
do not encounter a cycle and we reach to an element say for an example like six that does not have any prerequisites.
28:51:41
Then we can simply conclude that that node is a good node to be added to the stack. So we will simply add it to the
28:51:47
stack. Once adding to the stack, we will also add it to the node of visited nodes. What this would do is this would
28:51:54
allow us not to do redundant work or not to do duplicate work. So let's see the whole calculation in action. Okay. So
28:52:01
first we are going to start dfsing over the first element. So we are going to start with element number zero. If we
28:52:07
start with element number zero, what are the neighbors or what are the values for element number zero? Okay. So first
28:52:12
value is value number one. Right? So currently we are visiting. Okay. Initially we started our visit with
28:52:17
element number zero. Then first element we are visiting is currently one. Now we are going DFS which means we are going
28:52:24
in depth. So even for node number one we are going in depth. So node number one has uh is a prerequisite for course
28:52:31
number six. So which means if we want to get to course number six we will have to go through one. So now we will go to course number six. So currently we are
28:52:37
visiting course number six. Uh now course number six does not have any pre uh is not prerequisite for any of the
28:52:44
courses which means this is wonderful. So now what we can do is we can conclude course number six to be done. So we will
28:52:51
take the course number six value from here and we can actually add it to our stack. So if we add the value number six
28:52:59
to our stack. Okay. Now we have added a value number six which means course number six we have already put the
28:53:04
ordering for that. If we put the ordering for that which means we have already visited that course. So we are
28:53:10
going to add an entry in our visited hashet. Now for let's go back. Now if we
28:53:17
go back okay we still have one more element one that we haven't processed right so if we check for element one
28:53:23
does it has any other any other prerequisites or is it a prerequisite
28:53:29
for anything else apart from six no so which means this is done so for one we
28:53:34
do not have any more courses where one could be a prerequisite which means one can also be added to stack so we will
28:53:40
add entry number one to the stack as well and also at the same time we would define one has also been visited. Now we
28:53:47
go back to course number zero. So for course number zero currently we have taken care of this course number one but we haven't taken care of this course
28:53:54
number two. So we will keep on uh iterating. So currently now we would visit course number two. For course
28:54:00
number two do we have any ways to go to next course? Yes we need to go to course four. We will have to go to course go
28:54:06
through course two. So we can go to course four. Now for course number four does is it a prerequisite for anything
28:54:13
else? Yes, it is a prerequisite for course number five. So, in order to go to course number five, it has we have to
28:54:18
go through course number four. Now, for course number five, okay, course number five uh can go to course number six. But
28:54:26
the thing is six has already been visited. So, we can ignore this case. If we ignore this case, course number five
28:54:31
is not no longer prerequisite for any other courses. Which means now course number five is actually ready to be
28:54:38
added to our stack and also visited hashet. So, let's do that. We will remove course number five from here. We
28:54:43
will add that five has been visited and we will add an entry five over here. Awesome. Now we have course number four.
28:54:49
So for course number four, okay, apart from five, it did not add anything else. So which means course number four is now
28:54:55
also eligible to be added to the stack. So we will visit course number four and we will visit course number four to our
28:55:01
stack. Now for course number two, let's see if there are any more entries. No, there are no more entries. Awesome. So
28:55:07
now we will put course number two over here as well. So two added and also two
28:55:13
added two removed from the current stack. And now we are back to the course number zero. For course number zero.
28:55:18
Okay we already took care of course number one. Now we also took care of course number two which means zero is now also eligible to be added. So
28:55:25
awesome. Let's do that. So we add zero over here and we add zero over here. That's great. Now if we go back that
28:55:33
this has been jumbled up. So let me clean this up a bit. Now in this case
28:55:38
okay uh now we took care of course number zero right now for node number
28:55:43
one we will check our visited hash set. So in the visited hash set yes we have already visited course number one so we
28:55:50
don't need to do anything. Course number two has already been visited. Awesome. Course number three hasn't been visited.
28:55:56
So now for our current DFS we will start visiting course number three. Okay. So
28:56:01
for course number three it has many different prerequisites. Uh so course
28:56:06
number three okay course number three is a prerequisite for course number one so currently we are visiting course number three let's see course number one okay
28:56:13
one has already been visited so we do not need to visit this one four has also been visited we do not need to visit
28:56:18
this one five has been visited and six has been visited which means all of the courses which could lead us to these
28:56:25
courses have been visited which means course number three is no longer prerequisite for any other courses so it
28:56:31
is a good candidate to be added to our stack and our visited hashtag So we can add it to our stack and we can also add
28:56:37
it to our visited hash set. Right? Awesome. Now if we see our stack is already full. So do we need to worry
28:56:44
about adding these more courses or checking for them? No. But if you want we can do it. It would only be constant
28:56:50
time because all of them they have already been visited. So we don't care. Now since we have our stack ready let's
28:56:56
try to uh pop out all the values sequentially. If we pop out all the values sequentially this is going to
28:57:01
lead us to our answer. Why? Because okay first we have to complete course number three then 0 then 2 4 5 1 and 6 if we
28:57:11
complete courses in this manner we would be able to meet our prerequisite. So
28:57:16
let's see that whether our answer that we received uh is is this a valid answer or not. Let's compare it with the graph
28:57:23
that we created. Okay. So now we have both the values side by side. Let's see if we started trading. So if we first
28:57:29
complete course number three then we would be able to finish lot of different courses. So we do not have we won't have
28:57:36
any prerequisites for uh okay uh course number all of them have some other
28:57:42
prerequisites but if we do course number three there is no harm. So that is good. If we do course number zero that is also
28:57:48
good right now. Can we do course number two? Yes course number two only has prerequisite on zero which we have already completed. So we can do course
28:57:54
number two. Can we do course number four? Yes, course number four can also be done because we had it had prerequisites on course number two and
28:58:01
also course number three both of both of them have been done. Awesome. Now for course number five. Okay, five can also
28:58:07
be done because it had prerequisites on course number three and course number four both have been completed. Course
28:58:12
number one. Course number one only had prerequisites on course zero and course number three both have been completed. So we can do that. And also for course
28:58:19
number six, it had actually prerequisites on course number 1, 3 and five. All three of them have been
28:58:24
completed before. So this is a legitimate valid ordering that we can use and this is a great way to solve
28:58:32
this problem. See time and space complexity in this case the time complexity is actually going to be big of v + e where v is the number of
28:58:39
vertices and e is the number of edges. And if we see space complexity space complexity is also going to be big of v
28:58:46
plus e. And uh this is a great example. And also the way to find this ordering
28:58:52
is also topological sort. So congratulations to you. You also learned
28:58:58
a new algorithm. So since this video is already too long,
28:59:06
uh the code solution for this problem, I'm just going to explain it and then paste this code in the comments. So you
28:59:11
can check it out from there. Okay. So first of all, uh we are actually doing things a little bit differently than
28:59:17
what I explained. Basically, we are creating three different like white, gray, and black uh values. So this is
28:59:24
going to be assigned to every single node. White is going to represent that the node hasn't been visited or it
28:59:30
hasn't been touched so far. Gray means that during the current DFS this has already been visited. And black means
28:59:36
the code that is already going down into the u tag or that we have created which
28:59:43
means from where we can fetch it uh and use it for the answer. Now let's go to
28:59:48
our main method first. First we have this find order method where as an input
28:59:53
we are given number of courses and we are also given prerequisites. Now first thing we need to do is that based on the
28:59:59
prerequisite we are actually going to create the adjacy list. This is what we are going to create as I explained in
29:00:05
the explanation. Now after this adjacency list we are going to assign every single value to the white color
29:00:12
for the first time. Why white color? Because it hasn't been added to any list or it hasn't been visited. And then we
29:00:19
are going to go over every single values of this adjacy list and call our DFS
29:00:25
function. Now what does this DFS function is going to do? It is going to recursively call all of the values or
29:00:32
all of the neighbors of that particular node until we reach to the end. Now let's see what happens inside the DFS
29:00:38
function. We receive a node as an input. Now we have a boolean value is is
29:00:44
possible that is going to check that whether we have been able to find any cycle or not and how we are going to be
29:00:51
able to find a cycle by using this gray color. So if a node that is already
29:00:57
assigned a gray color and somehow in the DFS we find it to be gray again which
29:01:03
means we came back to the same node which we have already traversed during our current DFS. So there is a cycle
29:01:10
present. So this is a good way to detect that and for that we just created a
29:01:15
different method that if the given color is gray we simply get the DFS method uh
29:01:20
we simply assign the values uh is possible to be false. Okay. Now in this case first we assign the value to gray
29:01:27
for any any particular node that we are visiting then we start visiting all of its neighbors. Now for every single
29:01:34
neighbor we are only visiting the node that the color where the color is white. If the color is black, we are going to
29:01:40
ignore that. If the color is gray, we are going to assign the value is possible to false, which means that this
29:01:45
is not possible to do it and we can simply return an empty array in that case. If not, basically it recursively
29:01:53
we are going to call our DFS function for every single neighbor and for every single neighbor we are going to assign
29:01:58
the value to gray and we are going to keep on doing it until we reach to a point where it does not have any more
29:02:04
neighbors left. So at that time we are going to put the node and assign it color black and also we are going to
29:02:10
assign it to a topological order list that we have created recursively. If we keep on doing it basically our
29:02:17
topological order list is going to be basically our stack where we would have all the values filled up. And once that
29:02:23
is done from our main method we will check that okay if this is possible if that is true which means if this is
29:02:30
still possible then we will simply iterate over all the number of courses
29:02:35
and we are going to create a new array called order. For this order we are
29:02:40
going to take all the values in the reverse from the topological order and we are simply going to return the order
29:02:47
list that we just created. And this is the whole solution. So I would be posting this in the comments. So I hope
29:02:54
you understood it. And uh if we try to run the code, this runs perfectly fine. If we try to submit the code, the code
29:03:01
runs uh decently efficiently. And uh yeah, so uh let me know in the comments
29:03:07
what do you think about.
29:03:14
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. Today we are going to do a very important lead code
29:03:21
problem Pacific Atlantic water flow. And as you can see that this problem hasn't been asked in too many companies. So I
29:03:27
think it's the companies where this problem has been asked are really one of the most important companies in the world. Uh Google, Amazon, Uber,
29:03:34
Microsoft, Facebook, Apple, Bance which is a parent company of Tik Tok, Bloomberg. So you can understand the
29:03:40
scale that why this problem is important and what kind of companies ask this problem. And the thing is main intention
29:03:47
for understanding this problem is to not to understand the actual problem but rather the approach behind the solution
29:03:54
because that can become a base foundation for too many other problems.
29:04:01
There is lot of information in this problem statement but if we try to comprehend this using the picture it
29:04:06
really it's really simple to understand. So I'm just going to go over that. Essentially we are given uh a grid like
29:04:14
this. And we are told that this is actually an island on somewhere in the ocean. But
29:04:19
the thing is it is at the cross junction between Pacific Ocean and Atlantic Ocean. And the way it represents is that
29:04:27
this top and this left edges they are actually Pacific oceans. And this bottom
29:04:33
and this right edges they are Atlantic Ocean. So the and the second information
29:04:39
we are given is that all of these coordinates inside the given u island
29:04:45
represents the height of that particular area. And why the height is important because we are told that on this
29:04:51
particular island uh on this particular grid there happens to be lot of rain which means that uh rain falls and we
29:04:58
know the property of water that it gets transferred from higher height to lower height. We are also told that that train
29:05:05
at any particular cell can travel to can go to four directions. It can go to top
29:05:12
uh right bottom or left which means it cannot go diagonal in any scenario. And
29:05:18
the condition that if uh it can travel traverse from one cell to another cell is that if the height at any particular
29:05:26
given cell if it's greater than or equal to the cell we are trying to reach then
29:05:31
the water can traverse travel to that uh that cell which means suppose we take
29:05:38
this cell for an example the height for the cell is four which means if the rain falls on this cell we can conclude that
29:05:45
rain the rain water will go to cell three, it will also go to cell one and
29:05:51
cell two, but it would not go to this cell five because the height at cell five is greater than uh cell four, which
29:05:58
means that this is cell four and this is cell five. So, water can't travel like this.
29:06:05
Now the interesting part for this question is that we need to understand that what are the uh cells in the given
29:06:14
grid that can travel where if the rain water falls it can travel to both
29:06:20
Atlantic Ocean and also Pacific Ocean. So let me clean this up a bit.
29:06:26
Suppose we consider this uh cell number five and if rain water falls in the cell number five let's see that can it reach
29:06:33
Atlantic and Pacific like we know it can reach but in this uh cell adjacent to
29:06:40
the cell number five the height is three which means water can go over here from this three the water can go to this one
29:06:46
and because this is at the edge of Atlantic uh of course water can go to Atlantic Ocean from here. Now from this
29:06:53
uh cell number five uh we know that water con can also go on this side because the height is four and from this
29:06:59
four the water can go because the height is two which is less than four and from this this is at the edge which means
29:07:06
that at any point whatever the height over here is like 1 2 whatever value all
29:07:11
of that can go to Pacific Ocean. So we can conclude that water from this cell number five can reach to both Atlantic
29:07:17
and Pacific Ocean. Let's take another example. Suppose we take an example of this uh value number four. So we know
29:07:25
that from this cell we cannot go over here. We cannot go to five but we can go
29:07:30
to two and from two we can go to Atlantic. So that concludes one one u
29:07:36
option. Now let's try to see that can we go to Pacific Ocean. So first if we try to go on top okay we can go over here
29:07:43
because this is three but from three we cannot go to the top because this is uh
29:07:48
four. So we can't go Pacific in that this direction. If we try to go over
29:07:53
here, we can reach to this one. We cannot go to this seven. Which means that from this four, we can go to
29:08:00
Atlantic Ocean, but we cannot go to Pacific Ocean. So we wouldn't include this in our intersections.
29:08:06
For every single cell, we are going to check that whether it can reach to both Pacific and Atlantic Ocean. If it can
29:08:13
reach, we will just maintain a list or some sort. uh that will take care of all
29:08:18
the cells that we are able to reach uh to both the oceans and we would keep on adding them in in this list. So first
29:08:26
we'll start with this first element. We know that it can reach to Pacific Ocean but it won't be able to reach Atlantic
29:08:32
Ocean because height over on both these cases are greater. So we wouldn't include this. We would go to next one.
29:08:38
So over this this again can reach to Pacific but it cannot reach to Atlantic because if we it will traverse in these
29:08:45
two directions but it won't be able to go any further over here and over here. Uh same happens for this one for this
29:08:52
one and uh basically this solution would work. We would find our answer eventually our list would be filled out.
29:08:58
Suppose we are at this location five. So we know that this is at the inter exact intersection of both the oceans and it
29:09:06
can clearly go to uh the rain water can clearly go to Pacific and both Atlantic. So we would add this particular location
29:09:13
in our uh list and uh eventually the list will be filled out. But the thing
29:09:19
is uh the issue with this approach is that in terms of time complexity we are
29:09:24
actually doing lot of lot of repetitive work because for every single cell we are checking all the possibilities and
29:09:31
uh we might end up doing in the worst case scenario big of so suppose this uh
29:09:36
is m and these are n cells. So we can say that the time complexity would be
29:09:41
big of multiply by n squared because for every single cell we will have to
29:09:48
iterate over all the other cells and uh this is not a very good time complexity
29:09:54
there is there exist a better approach so in order to solve this problem we are
29:10:00
actually going to use a different approach and we are the approach we are using is actually if mountain cannot come to Mohammad Muhammad will have to
29:10:06
come to mountain and what I'm trying to say is suppose that rather than checking at any particular cell that whether it
29:10:12
can reach both Atlantic and Pacific Ocean, we create two separate grids. So suppose we create a grid and uh another
29:10:20
grid. So two separate matrix of boolean values that has the same size of whatever the input size we are given.
29:10:27
And at any particular location we just name that that okay this matrix consists
29:10:33
the data of all the cells that can actually reach the Pacific uh
29:10:38
ocean and this cells contains this matrix contains all the data of all the
29:10:44
cells that can actually reach to the Atlantic Ocean. And once we have these two matrixes defined uh the moment we
29:10:52
find that okay so over here we know that uh this particular element three this
29:10:57
can reach to Pacific Ocean. So over here suppose this value corresponds to this three. So we will set the value as true
29:11:04
over here and uh same goes on this side that suppose we find out that this particular element at position four can
29:11:12
reach to Atlantic Ocean via this way. So whatever the corresponding we have value
29:11:17
we have over here we will set that value as true and eventually we will have the entire uh matrixes filled out and once
29:11:26
we have those all we need to do is just intersect both of them and find the common elements between both of these
29:11:32
matrix and uh that would be our final list of matrix that contains all the
29:11:38
cells that can reach to both Pacific and Atlantic Ocean and this would be our solution. Well, this solution actually
29:11:45
works pretty fine. It's pretty efficient. And uh all we need to do is we need to figure out that how we are
29:11:50
going to generate these two matrix and what are all the different logic we are
29:11:56
going to take. Let's take the most basic approach. I'll be showing you an example that suppose we want to reach to Pacific
29:12:02
Ocean. How can we fill out that ma matrix? Now what is the most basic thing
29:12:07
we know about Pacific Ocean? Well, we know that for this particular island, all the cells that are that are present
29:12:14
in this row and all the cells that are present in this column, they are actually at the edge of the island also
29:12:20
they are at the very uh adjacent to Pacific Ocean which means all the water
29:12:26
in these positions can actually reach to Pacific Ocean in all the cases. So in
29:12:31
our matrix or whatever matrix we have we can basically define all the elements
29:12:38
these positions as true because we know that they can reach to a Pacific Ocean.
29:12:43
Now previously at any particular location we were actually trying to go
29:12:49
outwards to see if water can reach to adjacent cell or not. But rather than going outwards why don't we come inwards
29:12:56
from the cells we already know that can reach to Pacific Ocean. So over here these cells we already know that can
29:13:02
that they can reach to Pacific Ocean. So if we check that whatever the cells that
29:13:08
are adjacent to these cells from this particular cell that can reach to Pacific Ocean can we reach to the these
29:13:15
adjacent cells or not and the moment we find that okay we can reach to some adjacent cells that we haven't already
29:13:21
visited. So we can set that as true. Suppose the value over here is three and
29:13:26
we know that this is able to reach to Pacific Ocean and suppose the value adjacent to this one is actually six. So
29:13:33
we know that uh since the height difference there is a height difference and uh over here we need to check the
29:13:40
reverse height difference. Previously uh in this approach we were actually checking that whether the height we are
29:13:47
currently at and the height the adjacent cell is actually uh the height is lesser
29:13:52
than whatever the current height we have over here we are coming inwards. So we will check that whatever the next cell
29:13:59
is that we haven't checked whether its height is greater than whatever the height we currently are at. So in this
29:14:06
case this is three this is six which means that okay from this cell we can come to this cell and uh over here we
29:14:13
know that we are coming to this cell from this particular cell that is
29:14:18
already able to reach to Pacific Ocean. So over here we can directly mark this one as true and we won't have to do lot
29:14:26
of calculation over here because we already know that this cell is true and we are reaching to this cell via this
29:14:32
cell and this would be a very good solution and this is how we can actually
29:14:37
fill out this entire matrix or like all the remaining portion in big go of m
29:14:44
cross n*s in just single traversal because we are not for any particular cell we are not going to check the whole
29:14:50
thing we are only going to check the cell that is exactly adjacent to it. Suppose we are at this particular cell
29:14:57
and we know that this cell can reach to Pacific Ocean. We have already set this value as true. Okay. Now uh we do
29:15:04
calculations like this and suppose before we come over here uh from this
29:15:11
route we have already calculated this and we know that this is already true that this can already reach specific
29:15:17
ocean and we are at this position and we are checking this again. So first we will already find that whether the value
29:15:24
for this particular element has been calculated already or not. If it has been calculated, we don't need to do
29:15:30
repetitive work and we can just simply skip over it. Uh so that way we can also make uh some runtime adjustments that
29:15:37
would be more efficient on our case. Okay. Now we need to find a way to somehow create the matrix that stores
29:15:44
the information of all the cells that can reach to Pacific Ocean and also to Atlantic Ocean. uh in order to do that
29:15:52
at first I thought that we are going to use dynamic programming over here and the reason I thought is because first of
29:15:58
all we are defining a set of uh all the cases that can reach to Pacific Ocean.
29:16:04
So this becomes our base case. Once we have our base case defined uh we are essentially going in all the directions
29:16:11
to see that if we can reach to next cells and suppose in this case we are able to reach to this cell from over
29:16:16
here due to the height difference. So we will mark this as true and uh again from
29:16:22
over here we will again do the same thing and we will so basically at any
29:16:27
point we are using whatever the calculation we have calculated before to generate the next results. So that's a
29:16:34
very clear indication that we we need to use dynamic programming over here. But it turns out that I was not not able to
29:16:40
solve it efficiently. I was still missing out in a lot of test cases. So apparently dynamic programming is is not
29:16:47
the way to go but I still urge that if anyone can solve it using dynamic programming I would be uh more than
29:16:53
happy to understand your approach. So second thing I tried to do is uh that
29:16:59
okay in order to solve this we need to iterate over the entire matrix and uh in
29:17:04
order to iterate over the entire 2D matrix we we can use we have basically two methods we can use either breath
29:17:11
first search or we can use depth first search to iterate over all of the elements and do some calculation now I'm
29:17:18
new to graph theory and I need to first of all perfect myself on depth first search before I move towards solving the
29:17:24
problems using breath first search. So I chose the approach of taking depth first
29:17:29
search but it can also be solved using breath first search without any issues and we know that in order for us to sell
29:17:36
uh to complete this program using depth first search we need to use recursion over here and uh of course we can use
29:17:43
recursion because notice that at every single position uh so over here first of
29:17:48
all we define that this can reach to Pacific Ocean. Now we move on all the directions and over here we find the
29:17:55
height difference. So again we know uh that uh this can reach to Pacific Ocean because this can reach to this cell. So
29:18:01
we mark this as true and then again we repeat the same process that we have
29:18:06
just did and again we would mark this as true and again we would repeat the same process. So essentially we are doing the
29:18:14
same sort of work but for different inputs and that's a very clear indication that we we need to use depth first search uh using recursion and uh
29:18:22
let's move on towards coding now. First of all we are going to check the condition that if uh the given input is
29:18:29
actually an empty matrix then we just need to return null.
29:18:36
Okay. If that's not the case uh let's create two parameters to store the value of row and column.
29:18:43
Now we'll create two boolean matrix to see uh if the to store the value of
29:18:49
cells that can reach to Pacific and Atlantic Ocean and we are going to name that Pacific reachable and atlantic
29:18:55
Atlantic reachable and we are going to create both of them
29:19:01
to the size of whatever the uh initial heights matrix we are given.
29:19:08
Now we will run a for loop on the for both the matrix matrix to be filled out.
29:19:16
In order to fill both the matrix we are going to create a DFS method. And inside
29:19:21
the DFS method we are going to provide the row and column location.
29:19:27
And uh we are also going to provide Pacific and Atlantic matrix. So first
29:19:33
we'll do it for pacific matrix and we are also going to provide uh the input
29:19:39
heights that we are given. We are again going to call the same
29:19:45
function for the Atlantic
29:19:50
we'll iterate using column as well.
29:19:55
Now before we calculate the result first let's create the method.
29:20:03
Now inside the DFS method we will have to iterate over for any particular cell we'll have to iterate over all four of
29:20:10
its uh adjacent cells. So we'll just create a 2D array called uh directions
29:20:18
and we are going to use it uh to iterate over all the adjacent uh or neighboring
29:20:24
cells. So we are at this DFS location which
29:20:30
means that we already know that this row and this column pair is already able to reach to subsequent whatever reachable
29:20:38
uh matrix that we are trying to calculate. So which means that we will set that value as true.
29:20:46
Now we will start iterating over the neighbors of whatever the current cell we are at.
29:20:53
And we are going to create the new row and new column.
29:21:00
Now we will have to check that if this uh new row and new column are they out of bounds or not.
29:21:09
If that's the case, we just ignore that uh and we continue.
29:21:16
We also check that if we have the if the new row and column uh cell have we if we
29:21:23
have that value calculated before, we can also just ignore that case.
29:21:30
Okay. If both the cases are not true, uh we will check that if the height
29:21:35
difference of the previous cell and new cell is in our favor or not. Which means
29:21:42
if the heights for the new row and new column
29:21:50
if that is greater than or equal to whatever the previous height was.
29:22:00
If that is true, we will need to call the DFS function again with the new row
29:22:05
and new column
29:22:15
and uh this this would be our logic for this DFS method because we are
29:22:20
eliminating all the cases and we are also uh calling the recursive function based on the height difference. So after
29:22:28
these four uh entries run, we should have both of our Pacific reachable and
29:22:33
Atlantic reachable matrixes filled out. And now it's just a matter of finding the common elements between them. So
29:22:39
first of all, let's create a list of lists uh to store our result. And we'll just name it as result.
29:22:48
Just going to iterate over the entire array uh row and column wise.
29:22:54
And we are only going to check that if both the values are true in both the Atlantic and Pacific Ocean cells. So if
29:23:04
if both are true, we can add it to our list. So
29:23:13
uh after this loop runs, we simply need to return whatever the result we found.
29:23:19
And uh that should be our solution. Let's try to run this code.
29:23:25
Okay, seems like our solution is working. Let's try to submit this code.
29:23:31
Okay, our solution also works. It is uh accepted by lead code. But the thing is it's it's not the most efficient uh
29:23:40
solution. So let's see that if we can do some modifications and uh one modification I can think of
29:23:46
is uh rather than calling this DFS system right here and checking this
29:23:51
condition all the time what if we revert the condition and if this condition is satisfied we can return we can just uh
29:23:59
return it and we can just continue before so that's why loop breaks more
29:24:05
times before and uh if all of these conditions are not true then only we
29:24:11
will call our DFS function. Let's try to run the code. Okay, the code is working.
29:24:16
Let's try to submit the code. Okay, we see some improvement in our code and now it's a little bit faster than what our
29:24:23
previous result was. So, I'll be posting this code in the solution. You can check
29:24:28
it out from there uh from the comments and uh let me know if how do you like
29:24:34
the video. Thank you.
29:24:44
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better
29:24:50
at technical interviews. Keeping with that goal in mind, today we are going to do a very interesting lead code problem. So let's get started with that. So today
29:24:57
we are going to do find the celebrity lead code problem and if we see some of the popular companies the problem has
29:25:02
been asked at companies like Amazon, LinkedIn, Pinterest, Microsoft, Facebook, Apple, Snapchat, Google, Uber
29:25:07
and Goldman Sachs. So basically all the popular companies have asked this question. So I'm going to pay my utmost
29:25:13
attention. I hope you also enjoy the video. This has to be one of the most
29:25:20
interesting problems I have been able to find so far. If you look at this lead code categorize this as a medium
29:25:26
problem. If you try to understand the problem statement and try to think about it, you will feel like this is actually
29:25:32
a hard problem. And once you put like some more thought into it, you are actually going to feel that this is
29:25:38
actually an easy problem. So in my opinion, this is actually an all-in-one problem. Let's understand the problem
29:25:44
statement to go further deep. It says that suppose we are at a party with n
29:25:49
people and the names of these people are the numbers. So basically numbers from 0
29:25:55
to n minus 1. So say for an example we are in a party with four people. Basically the people are going to be 0 1
29:26:01
2 and 3. So these are going to be the four people. Now we are told that in
29:26:07
this party there may exist. So this is an important part that there may exist
29:26:12
which means there might be a celebrity or there there might not be a celebrity.
29:26:18
Okay. Now we are first of all given that what the definition of a celebrity is.
29:26:23
The definition of a celebrity is that that c that every single person in that
29:26:29
party knows who the celebrity is. And the second condition is that celebrity
29:26:35
does not know an any single person in that party which is how typical celebrities are. So now given these two
29:26:42
definitions first of all we are told that we need to check that whether there
29:26:47
exist a celebrity or not and if there exist a celebrity basically we can uh we
29:26:55
need to find that who that celebrity is. The question is how we are going to find who that celebrity is. Well, definitely
29:27:02
over here the relationship is based on uh either people knowing who the
29:27:07
celebrity is or the fact that celebrity knows no one that everyone knows
29:27:12
celebrity and celebrity knows no one. Right? Now at our advantage we are given a methodology where we can check between
29:27:20
any two entities whether they know each other or not. We have a method boolean knows A to B which defines that whether
29:27:27
A knows B or not. If A knows B, if this gives answer true, which means A knows
29:27:32
B. If this gives answer false, which means A does not know B. And why we are using that? Because the only
29:27:38
relationship we have to identify whether a person is a celebrity or not is by the
29:27:44
amount of people know them or the amount of people they know. And in this case,
29:27:50
we either need to find the celebrity or we need to return minus one if there if no celebrity exists. So I know this is a
29:27:57
little bit complicated to understand but let's try to see some examples for this problem. Okay. So in the problem we are
29:28:04
actually going to have an input that looks like this. Uh where in this input we are given a list of list that
29:28:12
contains some values uh that defines the relationship between any two values that whether they know each other or not. Now
29:28:18
the thing is this input is kind of messy. So I'm not actually going to show you uh examples based on this exact
29:28:25
input. I'm actually going to show you in the base of something that is easier to visualize. So this is the same input I
29:28:32
took from here but I have actually converted it into a 2D M matrix and basically as an input we are given a
29:28:38
graph or we are basically given an adjacency matrix. Okay. Uh so for this adjacy matrix we based on this adjacy
29:28:47
matrix we are given two entities. We are given a person and we are given whether that person knows each other or not.
29:28:52
This diagonal line is always going to be one because that defines that whether person zero knows person zero or not.
29:28:58
Whether person one knows person one or not things like that and that is always going to be one. So we can simply ignore
29:29:04
this one. The this serves no purpose. Uh the important thing in this case is this defines that whether person zero knows
29:29:11
person one or not. So this answer is one which means that person zero knows person one. Let's try to find who the
29:29:18
celebrity is in this problem. Right? So in this case we are given basically three person. So we can actually create
29:29:24
a graph that looks like this of three person and we are going to name them as 0 1 and two. Right? Now the thing is
29:29:30
relationship between them is actually going to be the relationship defined by an edge where a edge would represent
29:29:37
that whether one entity knows the other entity or not or one node knows the
29:29:42
other node or or not. And this is going to be a directed edge. Why? Because it could be possible that 0 knows one. But
29:29:49
one does not know zero. So we cannot just simply have an undirected edge. We must have a directed edge in this case.
29:29:56
So let's try to do that as well. So if we draw it from this this graph, okay, 0 0 this does not matter these three
29:30:03
values. So we'll just ignore them. Let's just start 0 with one. So 0 knows one, right? So which means 0 knows one. Yeah,
29:30:09
we mark it. Now does 0 know two? No, 0 does not know. So there is not going to be an any edge. Now whether one knows
29:30:16
zero, no, one knows one does not know zero and one also does not know two. So one does not know anyone. Now in this
29:30:23
case whether two knows zero. Yeah. So two knows zero that is good. And whether
29:30:28
two knows one. Yeah. Two also knows one. So that is also good. And two knows two. Yeah that is true. So we can ignore
29:30:34
that. In this case if we see if we see the two definitions of a celebrity that
29:30:39
everyone knows who the celebrity is and celebrity knows no one at the party. So
29:30:44
definitely in this case we can say that hey if we check out the input for this value number one it knows itself but the
29:30:50
thing is that is not the point it the point is whether it knows anyone else at the party or not. So one does not know
29:30:56
anyone at the party. That is true. And also zero knows one and two also knows one. Which means every single one who is
29:31:05
every person every person other than one knows who the one is. And one does not
29:31:10
know anyone. Which means one perfectly fits on our category of celebrity. And in this case one is going to be
29:31:16
celebrity. So we will simply return one as the answer. And this is what we need to return. Okay. Let's see one more
29:31:21
example. In this case again 0 1 and two. Uh let's draw three lines. Now ignore
29:31:27
these three cases. And 0 knows uh one. No. 0 knows two. Yes. So 0 knows two.
29:31:33
Okay. Does one know two? Yeah. One also knows two. That's good. Now whether two Okay. Two knows zero. So in this case
29:31:39
two knows zero and two knows one. No. So in this case can we find any celebrity?
29:31:45
Actually we cannot find any celebrity. Why? Because in this case okay 0 and one
29:31:50
both of them know two. So that is good. Two qualifies for one of the property of being a celebrity. The thing is second
29:31:56
property of being a celebrity is that it has to know no one at the party. But in this case two actually knows who the
29:32:03
zero is. So because to know one person two does not qualify for the second entity of our answer. So in this caseh
29:32:10
we cannot find any celebrity. So because there is no celebrity present we are simply going to return minus one as the
29:32:16
answer. And this is what we need to return. Okay. So, first approach is a brute
29:32:22
force approach. In the brute force approach, what we are going to do is we are simply going to check that whether all the person that are given can any
29:32:30
single one of them uh is a celebrity. So, for one by one, we are going to check for every single person whether
29:32:35
they are celebrity or not. So, in this case what we are going to do is first we will take consider person zero. Okay.
29:32:41
So, for the person zero we will try to see whether zero is a celebrity or not. How can zero be a celebrity? If everyone
29:32:47
else knows who the zero is and zero knows no one. So in this case we can see
29:32:52
that zero knows someone. So zero is not a celebrity. Now we will have to check whether one is a celebrity or not. So in
29:32:59
this case okay one one still knows someone. So one cannot be a celebrity but and in this case we'll try to see
29:33:05
whether two is a celebrity or not. So two knows no one. And uh let's see that if everyone knows two or not. So this
29:33:11
one does knows two but this one does not know two. So two is also not a celebrity. So in this case we will return a minus one and this logic leads
29:33:19
us to the correct answer. Some maybe if you make some modifications or tweaks it can be an acceptable solution as well.
29:33:26
The thing is this is still not the most optimal way to solve this problem. So basically we would end up solving this
29:33:31
problem in big go of n square time. So which is not too bad for some of the
29:33:37
problem but it is really bad for this problem because this can be done very efficiently with other methods. So let's
29:33:44
try to see what that other methods could be. So in this scenario if we see okay 0
29:33:51
knows one and two so zero knows one and two right uh same way one does not know anyone and two knows one and uh one and
29:33:58
zero so two knows 0 and two knows one. So basically answer is going to be one that is a given fact. The thing is uh
29:34:05
what is one smart trick we can use? The smart trick is the nose function. The
29:34:10
nose function that we are given in the input that is there for a reason. And
29:34:15
what nose function does is that if we provide any two values say for example if we provide the values of 0 and one it
29:34:21
is quickly going to tell us that whether 0 knows one or not. So in this case okay
29:34:27
0 knows one that is a true fact. Now the thing is if we know for sure that 0
29:34:32
knows one. What is one thing we can say for guarantee? We can say for guarantee
29:34:38
or for certainty that zero cannot be a celebrity. Why we can say that? Because
29:34:43
remember the definition of a celebrity. The definition of a celebrity is that everyone knows the celebrity and
29:34:49
celebrity knows no one. Which means in this case if we try to find uh or if we
29:34:56
try to see this nose function between 0 and 1 and the answer is true. If the answer is true, definitely we can say
29:35:02
that 0 cannot be a celebrity which means we are eliminating zero. Now what could
29:35:07
be the second possibility? Second possibility could be say for an example if we try to use the nose function for
29:35:14
values 1 and two. If we try to use the function 1 and two knows the answer is
29:35:20
going to be false. Why the answer is going to be false? Because one does not know two. If one does not know two, what
29:35:27
is also one more thing we can say for certainty? Well, we can say for certainty that in this case two cannot
29:35:34
be celebrity. Why two cannot be celebrity? Because we found at least one
29:35:39
element that does not know two. And in order for two to be celebrity, celebrity
29:35:45
has to be known by everybody else in the in the party. So because we find one
29:35:51
entry over here who does not know two we can say for sure that two is not a celebrity which means depending on the
29:35:58
result of this nose function if the value is true we can eliminate one value that is the first value in the nose
29:36:04
function. If the value in is false we can eliminate the second value inside this uh given input which means with
29:36:12
every single nose call we are getting rid of one element. So in this case
29:36:17
after just making two calls we were able to get rid of zero and two which means
29:36:22
if there exist a celebrity it has to be one. So now all we need to do is that
29:36:28
since this is the last item or last value pending do we need to check that whether everyone knows one or not? No.
29:36:35
Why? Because since we know for sure that these two are not the celebrities. Right? So all we will have to worry
29:36:41
about is that whether one knows uh no one. If one knows no one which means one
29:36:48
has to be the celebrity. If one knows at least one person which means there are
29:36:53
no celebrities inside this input and we can simply return minus one. And this is the whole logic behind this problem. Let
29:37:01
me try to explain very quickly with a big example. So now we have bunch of different values
29:37:07
over here. Basically we are simply going to use the knows function and we are going to go through every single value
29:37:14
and try to see whether it knows the next value or not. So first we'll try to see that whether the zero knows one or not.
29:37:20
So and we can ignore all of these values because diagonals doesn't matter. We do not care if they know their own self or
29:37:26
not. So in this case okay 0 to one. 0 does not know one which means we can say
29:37:31
for sure that one cannot be celebrity. If one cannot be be celebrity we can simply skip over to the second value.
29:37:38
Now in this case we will check that whether 0 knows two. So in this case 0 to two 0 knows two. So because 0 knows
29:37:46
two we can say for sure that zero cannot be a celebrity. So we ignore this. Now we are at this value number two. So
29:37:52
we'll try to see whether two knows three or not. So 2 2 3 if we check okay two knows three. So if two knows three
29:37:58
definitely two cannot be a celebrity. So we will ignore that. Now we are at this value number three. So we'll check check
29:38:04
for 3 to four. So 3 to four if we check yeah three knows four. So in this case
29:38:10
three cannot be a celebrity because three knows four because of this value. Now we are at this four position number
29:38:15
four. Four to five. So if we see four to five so four to five uh this value is actually zero which means four does not
29:38:22
know five. So because four does not know five five cannot be a celebrity. So in this case we have actually got rid of
29:38:28
all of these elements and only fourth value is pending. So now we know that if
29:38:33
there exists a celebrity it has to be four otherwise there are no celebrities. So now we are simply going to check that
29:38:39
whether four knows anyone or not. And for that we simply have to do one check at this fourth row to see whether apart
29:38:47
from four by itself does it know anyone else and it knows no one. So definitely
29:38:53
four uh four is the only candidate left and four knows no one. So in this case
29:39:01
four is definitely our celebrity and this we can simply return as the answer
29:39:06
and this is the whole logic behind our answer. Say for an example in this case by chance if four knew this value number
29:39:14
one. If this was answer one then simply we can say that okay four is also not a celebrity and we can simply return minus
29:39:20
one in this case. But thing is because this value is actually zero. So in this case answer is actually going to be four
29:39:26
and we are solving this problem most efficiently. If we see time complexity in this case the time complexity is
29:39:32
actually going to be big of n. And if we see space complexity well apart from using couple of variables we are not
29:39:38
using any additional space. So space is actually going to be constant.
29:39:45
First I identify few things. So I created a new global integer to use the
29:39:50
number of people and I have assigned it the to the value of n. And basically in the problem we need to resolve this find
29:39:56
celebrity problem. Uh and also for this problem I have created is celebrity a
29:40:02
helper method. So that is going to define that whether any single candidate that we have been able to identify from
29:40:08
this find celebrity method if that is a celebrity or not. And uh now first let's
29:40:14
start implementing this find celebrity method and then we will implement our is celebrity method. So first of all we are
29:40:20
going to uh initialize a variable called celebrity candidate. Now we are going to
29:40:26
run our for loop and for every single value we are going to check or we are
29:40:32
going to call our nose function and for the nose function we are basic basically providing the value of the celebrity
29:40:38
candidate and the value of uh current I. Now depending on the answer we get back
29:40:45
we are going to update the value to the i. So what this is going to do is this is
29:40:51
simply going to eliminate every single value for us except one last remaining candidate and that we are going to
29:40:58
consider as the celebrity candidate. And once we get out of the loop all we will have to do is we will have to call our
29:41:03
is celebrity method. If this value is actually true if this value is a
29:41:08
celebrity we are going to return this. And if that is not the case we can
29:41:14
simply return minus one. Now in this method we will first of all run a for loop. Inside the for loop first we will
29:41:21
have to check that if the given value of i is equal to j which means we have found a diagonal value. So in this case
29:41:27
we simply ignore that and if that is not the case we are going
29:41:32
to check that whether j satisfy all the properties of being a celebrity or not. If any of these is true we can simply
29:41:39
return false. And if that is not the case and if we get out of the loop we
29:41:44
can simply return true. And I think this has to be the whole
29:41:50
logic behind this in uh input. So let's try to run this code. Seems like our
29:41:55
solution is working as expected. Let's submit this code and our code runs pretty fast uh
29:42:02
compared to lot of other solutions and it is also really efficient in terms of time complexity. So this was a great
29:42:08
problem to solve and to understand lot of different concepts. I will be posting this solution in the comments so you can
29:42:13
check it out from there.
29:42:24
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better
29:42:30
at technical interviews. Keeping with that goal in mind, today we are going to do a very interesting lead code problem called word letter that has a real life
29:42:37
application because this is a game by itself as well. And if we see some of the popular companies who have already
29:42:42
asked this question, there are companies like Amazon, Bloomberg, LinkedIn, Microsoft, Google, Uber, Apple,
29:42:48
Facebook, Lyft, Bite, Dance and Goldman Sachs. So that's why I'm paying my utmost attention. I hope you also enjoy
29:42:54
the video. So this is a lead code hard problem and also very well-like problem which is a
29:43:00
rare combination to be seen. Now in this problem we are given two words a begin word and an end word and we are also
29:43:06
given the list of words called dictionary or word gest. Now our aim is
29:43:11
to reach or go from the beginning word to the end word by a transformation
29:43:16
sequence. The question is how does this transformation sequence works? Uh well the transformation sequence works is
29:43:22
that suppose we are currently at word one. We can only jump to word two if the
29:43:29
charact the difference between the characters is only one. So say for
29:43:34
example if we are given a word like cat and we are given the second word like cot we can go from cat to cot because
29:43:41
there is only difference of a single character a uh the c and t are common across both the words. So this is a
29:43:48
valid transformation sequence. The idea is that from the beginning word we need
29:43:53
to keep on doing the transformation sequence amongst many different words and our aim is to reach to the end word
29:43:59
somehow. And if we are able to do it we need to see that what is the minimum
29:44:05
number of ways we can do it and these words they has to be present inside the word list that we are given. So we
29:44:12
cannot just create words out of fly. This is this is the purpose of this word list uh set that we are given that we
29:44:18
are given bunch of different words and if somehow we are not able to reach to this end character uh using the
29:44:25
transformation sequence we need to return zero and if we can we need to return the minimum number of hops needed
29:44:31
to reach to there. So let's try to understand this with couple of examples. If we see this first example here the
29:44:37
begin word that we are given is called hit and the end word is cog and these are the different words that we are
29:44:42
given. So one of the ways we can solve this problem is by creating a word sequence that looks like this. In this
29:44:50
case we are starting from the first word and we are reaching to the end word. And these are all the different hops that we
29:44:56
are making using the transformation sequence. So this is a valid example. But if we see in this case we are
29:45:01
actually taking six different hops to reach to the end word. Can we do something better? And the answer is yes.
29:45:07
There is exist a better solution for this problem. So let me quickly show you the better one. Now again even for this
29:45:13
example we are able to reach from this beginning word to the end word but in this case we are doing the whole journey
29:45:19
by only five different hops. So in this case we need to return five as the answer because we are only taking five
29:45:24
steps to reach from the first word to the end word and this is going to be our word ladder. Uh if we take a look at the
29:45:31
second example in the second example the word we are given is hit and again end word is cog. So that is true. But the
29:45:37
thing is in this case we need to return zero. Why we need to return zero? Well, because this cog is actually not at all
29:45:43
present inside this word list that we are given. So since the end word is not present, we cannot reach the end word.
29:45:50
So basically we need to return zero. So I hope this explanation makes sense and you are able to understand the problem
29:45:55
statement. Now let's see that what is going to be the approach we will take.
29:46:00
Okay. So before we come up with the optimal solution first let's see that what kind of pattern we can see in this problem. Basically we are given a
29:46:06
beginning word and an end word and we are told that there are some series of words that we need to go to in order to
29:46:13
reach to this end word and we need to return the minimum sequence possible. Right? The thing is in this problem we
29:46:20
are not only guaranteed to given all the words that would be used between this beginning and end word and it could be
29:46:27
possible that we are given some different words that are not being used or they can be used but the thing is
29:46:33
that leads to like a longer answer and we do not need to like go through all of
29:46:39
them and we only need to find the shortest path. Now if you see this kind of structure what does this reminds you
29:46:45
of? Well, you are absolutely correct. This is actually a very similar structure to a graph where you can see
29:46:53
the words that are given they can be treated as different nodes and the
29:46:59
relationship between those these nodes can be treated as edges. So we have our vertices and edges and we have a way to
29:47:06
define edges. Now how does an a vertices connects to an edge? A vertices connects
29:47:12
to an edge through the mechanism that the number of characters of word one on
29:47:18
and word five in this case they only have one differing character and that's it. That is the only way we can define a
29:47:25
relationship between them. Once we have a structure like this ready now let's
29:47:31
see what is our aim. Our aim is to find a path from the beginning word to the
29:47:36
end word. And if we want to find the path what we can do is we can simply iterate over the given input and see
29:47:43
that what are the different paths we can take and try to find the most optimized
29:47:48
path or the shortest path that leads us to the correct answer. So in this case we can actually find two different paths
29:47:55
that leads us to the answer. First one is the one that I indicated in blue and second one is the one that I indicate in
29:48:01
this purple color. Now in both the cases this path is actually the shortest path
29:48:07
that leads us to the answer and in to in the end we need to return the distance between the words amongst these paths.
29:48:13
So in this case the answer is going to be five. But you get the idea that basically we can if we are able to
29:48:21
generate this graph structure then all we need to do is just we need to do the
29:48:26
breath first search traversal and the question is why breath first search? because we are trying to find the shortest path and if we do depth first
29:48:33
search it could be possible that in practice it might take us longer. So breath first search would be a better
29:48:39
candidate in this this case. So if we are able to create a graph structure and
29:48:45
if we do the breath first search we can actually find the shortest path.
29:48:54
Okay. So now we are going to use the same example that we have been given as the input. Now first of all we need to
29:49:00
find that uh the beginning word that we are given is the word hit right and say
29:49:05
for example we devis some mechanism to easily traverse through these words to make sure that whether these words exist
29:49:11
or not right now the question is from the hit we are treating this hit as one
29:49:16
of the nodes right now we need to find that what are all the different edges this hit is able to connect to the idea
29:49:24
we can do is that uh we can see all the possible words that this hit can have
29:49:32
with just one deferring character. The logic is we can start with the first character and keep all the characters
29:49:38
from A to Z and then keep the remaining two constant. So what we will do is we
29:49:44
will try to check for the words such as uh ait t then bi all the way up to zit
29:49:51
right these are all the different words we can make then same way we can keep the h and t common and then do a b c all
29:49:59
the way up to zed and we we can keep on repeating the same process. So basically
29:50:04
at every single word what are the different possible words we can have? Well, uh say for an example the len if
29:50:11
the length of this is equal to m then basically we can have m ult* by 26
29:50:17
differing characters and or differing word possibilities. Now amongst these 26
29:50:23
word possibilities all we need to do is we only need to find the words that
29:50:28
exist inside this word list. And since this is a dictionary basically we can
29:50:34
access pretty fast and check that whether any word exists or not. We can do it in constant time. So this is not
29:50:40
going to be an extra overhead. So by using this logic we are actually able to
29:50:45
generate all the graph pairs for our given input. So first value is going to
29:50:51
be hit. And now let me just quickly draw the graph structure.
29:50:59
Okay. So we can actually make a structure that looks like this. And this is a pretty decent representation of the
29:51:04
input that we are given. Now this is going to be our start node and this is going to be our end node or the
29:51:10
beginning word or and the ending word. Now basically we need to iterate over the given graph and we are also going to
29:51:18
keep track of all the nodes that we have visited so far. Uh that is to uh not end
29:51:23
up inside any uh like unexpected loop or infinite loop. Now all we need to do is
29:51:29
from starting point we already mentioned that we are going to run a BFS and we are also going to have a variable called
29:51:34
min that is going to keep track of what is the minimum path we have found so far. So if we just see the input one of
29:51:41
the path we can take is that we start from hot hit and then we can go down
29:51:46
this path and uh eventually we would be able to reach to the end word. So in this case if we see and definitely we
29:51:53
are going to keep track of all the visited nodes and everything is going to be taken care of. If we see this path
29:51:58
basically it is going to take us six words and currently this is the minimum value we have because we haven't
29:52:04
identified any other path right so six is the correct answer now what is let's see that if there is any second option
29:52:11
that we are missing so yes there is uh another option that we are missing and the option is that if we start from this
29:52:18
hit we can go down this path and through this path the number of words we encounter is actually five. So because
29:52:24
we are encountering five words basically we need to update the minimum number of answer we can get. Let's see if there is
29:52:30
any another path that we can take that we are missing. And yes there is also still one more path that we haven't
29:52:36
taken. And the path that that looks like this and in this path also we are
29:52:43
encountering five words. So again the answer is going to remain five and we have explored all the possibilities. So
29:52:49
in this case we can simply return five as the answer because that is what we need to create. And you see once we have
29:52:57
this graph kind of a structure ready things becomes much easier to comprehend and we can simply return the answer
29:53:03
pretty fast pretty efficiently. So this is the whole logic behind this problem. Now uh in this problem currently we are
29:53:11
only going in just one single direction. uh but uh in practice there can be like
29:53:18
a birectional uh BFS where uh we start iterating from here and we also start
29:53:24
iterating from here and we can do like BFS from this direction BFS from this
29:53:29
direction to reach somewhere in the middle and to find the answer and we we
29:53:35
can do things slightly faster in that cases but I don't think anyone is going
29:53:40
to expect you to do this in any of your interview So don't even bother. Uh if we
29:53:45
see time complexity in this case the time complexity is actually going to be bigo of m. So m is the number of length
29:53:52
of any character. And I mentioned that length is going to remain constant amongst all the word list characters. So
29:53:59
we don't have to worry about that. So number of m² now why m² m²
29:54:05
is taken in order for us to generate uh this graphlike structure. So it takes
29:54:10
big of m² time and for every single character there can be one possibility
29:54:16
that we need to because we know the starting and ending point. So basically it's going to be m² * n uh in terms of
29:54:23
the number of time complexity where n is the total number of words given and if
29:54:29
we see space complexity well basically we are anyway storing this graph-l like structure and that is going to uh give
29:54:36
us like go of m² space. So we also need to take care of that. So in my opinion
29:54:42
this was a tough problem but once you know the logic you can solve it easily
29:54:47
and this shows this goes to show you that if you know the logic about different data structures things becomes
29:54:54
much easier because this word letter game is actually a real life game that people use and people play. So yeah this
29:55:01
is not just a random out of the blue question. Now let's move on to the coding.
29:55:09
So since this word ladder problem was already becoming such a big uh video so that's why I'm just going to explain you
29:55:15
the code rather than typing all of it and I will go through the explanation. So first of all we are going to
29:55:21
initialize a variable to note down the word length because that is pretty important and we are also going to
29:55:27
initialize our hashmap that contains the information of all the combinations inside the dictionary that could be
29:55:34
possible. Uh now what we are going to do is for every single word that is present
29:55:39
inside this given word list we are basically going to iterate over all of its characters and we will try to see
29:55:46
that for all the differing differing characters what are all the transformations possible and whenever if
29:55:54
a transformation is possible we will basically add it to our all combination dictionary because this is a hashmap
29:56:00
inside the key we are going to store the value that is being present and uh
29:56:06
inside the word list and as its subsequent value we are going to have a list of all the possible combinations
29:56:13
that any particular word can have. So this is going to give us our uh dictionary and uh this is going to take
29:56:20
basically m² time to do it or l square time to do it. Now in order to iterate
29:56:25
over the breath first search we are going to have our Q where we will keep on adding or we will begin with the
29:56:31
first word and we will not rest until we have iterated over all the neighbors of
29:56:36
this first word and we will keep on repeating the same process iteratively. So we are not doing recursion. We can do
29:56:43
recursion but we are doing it iteratively and also as mentioned that because we do not want to get inside a
29:56:50
position where we end up in a in in any infinite loop. We are basically going to create initialize a hashmap and now we
29:56:58
are going to basically put the first word or the begin word that we are given as the input and then we will start
29:57:06
iterating over our given cube uh in the BFS fashion. So first of all we are
29:57:12
going to create a pair or so first of all we are going to uh remove the node in that is ex existent inside the
29:57:18
priority queue and then we will try to get its word value then we will see that
29:57:23
what level it is and basically we will iterate over all of the different word
29:57:29
possible words that can be present and we will keep on repeating the same
29:57:35
process for all the adjacent words and every time we go to the new level we are basically going to increase the size of
29:57:41
the level. So this is going to return us that how many different paths that we
29:57:47
have taken so far and somehow if we if we get out of the loop then basically we
29:57:53
need to return zero. So this is the whole logic behind the whole problem and
29:57:58
uh this condition refers to if we have reached to the end word and this condition refers to in the scenario
29:58:04
where we have not reached to the end word we have we are somewhere in the middle. So basically we are going to add a new entry inside our queue and we are
29:58:10
going to increase the current level we are at. So I think this solution makes sense. I would be posting this code in
29:58:17
the comments so you would be able to check out the code. Don't worry about it. Uh let me try to run this code and
29:58:23
our solution works as expected. Let's submit this code and our code runs decently efficiently in terms of space
29:58:30
complexity and time complexity. Both are really good. And this is the BFS solution uh from the lead code.
29:58:47
So the lead code problem we are going to solve now is called network delay time. This is a pretty popular lead code
29:58:52
problem. So let's understand the statement. Basically we are given a network of nodes marked from 1 to n. So
29:58:59
in total we are given three items. First one is times that defines that in order to reach from one particular node to
29:59:06
next node how much time it takes. So if we take a look at this example let's say 2 1 then we can say that in order for us
29:59:13
to reach from node number two to node number one it is going to take one unit of time. So this is how bunch of
29:59:20
different times we are given. Then we are given told k as a starting point and
29:59:25
that says that we will have to start iterating over our journey from k is equal to two. So in this case from
29:59:31
second node and this n defines the total number of nodes that we currently have. Now the problem is asking us to solve is
29:59:39
that we need to return the minimum time it takes for us to travel all the nodes
29:59:45
to receive the signal and if it is not possible for all the nodes to receive
29:59:51
the signal then we need to return minus one. So let's try to understand this with an example. Say for an example in
29:59:57
this case we are given an input like this. So we can see that in total we are dealing with four different nodes and we
30:00:03
are given three different edges. So first edges from node two to node number one it takes one time. Same way from
30:00:10
node two to node number three it takes one time and same way from node number three to node number four it takes one
30:00:17
time in order for us to reach. Now we are given K is equal to 2 which means starting from K we will have to make
30:00:23
sure that are we able to send a signal that reach every single node and what time it takes for to reach all the all
30:00:30
the nodes in the minimum. So during the very first minute we will have a signal that would that can go to node number
30:00:36
one and node number three. So we can say that these two nodes would have been visited after 1 minute and then from
30:00:43
node number three we still have to visit node number four. So we can say that in order to reach node number four it is
30:00:49
going to take one more minute which means it took 1 minute to reach over node number three and then one more
30:00:54
minute to reach to node number four. So in total it took us 2 minutes to reach to node number four and 1 minute to
30:01:00
reach to node number one and three. So in the minimum time two we can reach or
30:01:06
a signal can reach every single node starting from node number two. So this is what the problem statement is asking
30:01:12
us to return. Let's say in this case instead of two if we are being told that our k starting value is at three. So in
30:01:20
this case now we are starting our iteration from value number three. So once again we will have to check that
30:01:26
how many nodes can we reach. So we know that in the k three only points to one node. So during the first minute we
30:01:32
would visit node number four. But thing is we we don't have any way for the signal to visit to node number two and
30:01:38
node number one. So in this case we will have to return minus one. So this is the whole problem statement. Now let's say
30:01:45
that this is the input we are currently given and we are trying to deal with that how we can actually find the
30:01:51
network delay time starting from any particular node. The thing is we don't know that what node we are going to be
30:01:58
starting our code with. But all we have is the information about the total number of nodes that are currently present and the distance it takes in
30:02:05
order to reach from one particular node to other particular node. The logic is quite straightforward. We treat this one
30:02:11
as a classical graph problem where starting from any particular node we
30:02:16
will try to see that if there exist a shortest distance that can cover all the nodes that are currently present. If we
30:02:22
are able to reach to all the nodes then we will have to check check that which is the farthest node and how much time
30:02:28
it took us to reach to that particular level. Let's try to understand this within with this example that we were
30:02:34
starting our node at uh node number two and it took us 2 minutes to reach to node number one. Then the amount of time
30:02:41
it takes to reach to this node number three and node number one is obsolete because we are only concerned about the minimum time it takes to reach to every
30:02:47
single node and that should be our key focus. So few assumptions we can make is
30:02:52
that number one we can use this as a graph problem. This one is going to be the dysters uh problem that uh in order
30:02:59
to reach us to the shortest minimum uh uh span and I don't know the spelling of
30:03:04
dysters so sorry about that and uh no worry. Now coming back to the question
30:03:10
basically we need to number one thing is have a graph-like structure. So what I'm
30:03:15
suggesting is we create some sort of an adjacy list or adjacency matrix kind of
30:03:20
a structure. So let's say that we do create an adjacy matrix or hashmap that contains all the information related to
30:03:27
nodes and what are all the different distances that we can travel from those nodes. Now we all know that what are the
30:03:35
different uh edges it takes us for from any particular node that we can iterate over. So we because we are given the
30:03:42
information in this fashion like x y and t where x and y are the nodes and t is
30:03:48
the amount of time it takes to reach there. So we can just simply take this x put it in the node section. So this
30:03:54
would be the key for us to search inside our hashmap. And this y and t defines
30:04:00
that in order to let's say that in order for from x we we can have an information
30:04:05
like this one that y and one. So we can say that the node is x if we have to
30:04:11
reach to y it takes us one time. So let's try to build a graph like that for
30:04:16
all the nodes that are currently present in this case. But the thing is we are also going to do one thing smarter and
30:04:23
that is that instead of just pointing out the nearest neighbor any particular node can visit, we will also try to sort
30:04:30
these values based on the shortest value first and the longest value later. Why
30:04:36
are we doing that? Because we are trying to we have two objectives. Number one objective is to reach to all the nodes
30:04:42
and second objective is to do it in the minimum time. So we will have to find the quickest route possible. Next
30:04:48
objective is that we will have to iterate over all the nodes that are currently present. So we are going to
30:04:54
fulfill all of these goals by making some adjustments in the way we do our calculation. So for that first let me
30:05:01
just set up the graph structure that I'm suggesting and then we will start tackling over the other problems. Now in
30:05:08
this case we are only dealing with four nodes. So starting with node number two we have two options. If we have to reach
30:05:15
to node number three it takes us two times. So it makes sense that this is the shortest distance. So we can mark
30:05:21
the values as in order to reach to node number three it takes two times and in order to reach to node number one it
30:05:27
takes uh three times. So we are going to mark things like this. Same way starting at node number three once again we have
30:05:33
two options. In order to reach to node number four it takes us three times and same way in order to reach to node
30:05:39
number one it takes us six times. Same way from node number one we only have one option and that is in order to reach
30:05:46
to node number one it takes five times and from node number one we don't have any option. So at the node number one we
30:05:53
basically just don't have any edges that are going out. So we will not mark anything. Now we knew that these are the
30:05:59
four edges that we will have to traverse over. Next thing is that we also need to keep track that what are the nodes that
30:06:06
we have visited so far and also the other thing is we need to know that is the node visited if that is the shortest
30:06:13
distance that we found so far. Now in order to tackle both of this problem what I'm suggesting is we create a new
30:06:20
array uh that is of size n. So we will have values uh like this one like 0 1 2
30:06:26
3 and four. But the thing is in this case we are only dealing with nodes starting from 1 to n. So not from 0 to
30:06:33
n. So the thing is for the very first value inside the array we are just going to ignore this one. Okay. So let's say
30:06:39
that we ignore this and initially we will set this array up to a very large
30:06:44
value. So let's say that we are populating uh the entire array with the maximum volume value possible. And then
30:06:51
the only time we will update this array is number one if we find out a path to
30:06:57
reach to that particular node by some smaller value and number two uh if we cannot find that in the end it would be
30:07:04
able to show us that there are some nodes we are not able to reach. So we can just return minus one in those case.
30:07:09
So let's try to start iterating over our solution now. It would make much more
30:07:14
sense. Let's say that in this case our given k is equal to two. We are starting our iteration from node number two. So
30:07:20
what is the minimum time it would take us to reach to all the nodes. Now from at node number two we can see that the
30:07:26
very first possibility is that if we have to reach to node number three then we will have to do we can do it in two
30:07:32
times. Currently node number three has not been visited. So we found a shorter way to visit node number three. So we
30:07:38
will mark it by two and then same way we are going to ignore or pop this case out
30:07:43
from our given list. Basically we are dealing with a priority cube or a
30:07:49
hashmap like a structure. So inside the hashmap we will add the value number three but we will pop out this value
30:07:56
from the from the priority cube. Now from this node number three once again we are going to repeat the same process.
30:08:03
And by the way currently inside the priority cube we only have these two values present. So first value was uh 32
30:08:10
and second value was 1 3. Now now we add one more value that is uh the value 43.
30:08:16
So now notice that we popped one value out and we have two more values that we
30:08:22
will have to deal with. Okay. And we would keep on iterating in terms of priority Q and we would try always try
30:08:27
to find the shortest distance uh that that we will try to kick out. In this case both values are three. So let's say
30:08:33
that we decide to update node number one first. So node number in order to reach node number one we can do it in three
30:08:39
times. So let's mark this one. Now once again at node number one we don't have
30:08:44
anything. So we cannot add anything to our priority cube. Then we are located at our node number four. So sorry node
30:08:53
number three. So at node number three we added one value that is 4 three. And we
30:08:58
also have to add one more value that is 1 and six. So for the 4 three currently four has not been visited. So we would
30:09:05
mark uh value number in this case we would not mark value number three. Why? Because in order to reach to node number
30:09:11
three it took us two times. So we will have to do the sum with two. So in order
30:09:16
to reach to node number four it is actually going to take us five times. So we are going to mark four and five. And
30:09:23
same way if if we have to follow this path and reach to node number one then it would have taken us eight times. So
30:09:29
we are going to mark this as 1 and 8 inside our priority key. And this is the important step where we are updating the
30:09:35
total number time it takes in order to reach to that particular node based on the previous value we had for in order
30:09:42
to reach to that node. So in this case once again the node for four has not
30:09:47
been visited. So we will update it by value number five. But notice that this 18 does not need to be updated because
30:09:53
we already know that we can reach to 1 in three times. Then why would we choose a path that reaches one in eight times?
30:10:00
So we will ignore this one. And then now we are at four value number four. So from four we can we have one more path
30:10:07
then we can go in order to reach to node number one. And uh this takes five times. So if we choose that then it
30:10:14
becomes 5 + 5 so 10. But the thing is we still don't need to update because we already have value number three. Now the
30:10:19
thing is we because we are starting from k is equal to 2 which means from k is equal to 2 in order to reach to k is
30:10:26
equal to 2 it is only going to take zero time. So we should have updated this at the beginning. Uh so I forgot to update
30:10:33
but let me just do it right now that in order to reach to K is equal to two we can do it in zero times. And now we can
30:10:40
see that we are done with our entire iteration. Our priority Q has to be empty because we took care of all the
30:10:47
nodes and we are left with this array. Now in this array all we need to do is
30:10:52
we need to iterate over all the nodes. uh ignore the first node because we are only concerned with between 1 to nodes.
30:10:59
Check that if we found at any particular moment any value that was the original
30:11:05
max value that we started with. If that is the case, then we can simply return minus one saying that there were few
30:11:11
nodes that we were not able to reach. If we don't find any value with minus1, we are going to find that what is the
30:11:17
maximum value we have in this current array. And currently the maximum value is five. So we can say that five is the
30:11:23
to minimum number of time it takes for a signal to reach to every single node starting from k nodes and this is what
30:11:30
we can return. So this is a beautiful solution. It has lot of practical application like aviation industry uh
30:11:36
network routing industry all the things use methods like this in order to compute that what is the shortest
30:11:42
distance to travel from one uh one point uh of the plane to the other point of the plane which is pretty awesome and uh
30:11:49
pretty nice. Now let's try to understand the time complexity. Now it makes sense that we will have to do bigo of n
30:11:56
multiplied by v work for every single node and at every single node we will have to check that what is the shortest
30:12:03
distance for that we will have to add the those entries inside our priority q. So it is going to be multiplied by
30:12:09
logarithm of n and this is a pretty decent solution where n is the total
30:12:14
number of nodes and v is the total number of vertices and uh sorry not vertices but this should have been
30:12:20
edges. So n multiplied by e. If we look at the space complexity well we are
30:12:25
using quite number of additional data structures. We are using a graph-like
30:12:30
data structure to store all the values. We are using a priority queue. we are using bunch of different pointers and
30:12:36
stuff like that. So overall the biggest one is the graph-like structure that is bigo of once again vertices multiplied
30:12:42
by edges. So this is going to be the space complexity that we would be dealing with. So now let's quickly see
30:12:48
the coding solution for this one. So the very first thing we are going to do is that we are going to create a
30:12:54
graph-like representation using an adjacy list and for that we are using a hashmap to store the nodes as integers
30:13:02
and its subsequent edges as the link list uh type of structure. We are simply iterating over every single edges. We
30:13:08
are marking the very first node that we currently have as part of a key. And then the second value and the third
30:13:15
value is being represented as the edge and the time it takes to reach to that particular level. Then we are
30:13:21
initializing a new priority cube where this is going to be a min heap and we are going to be checking that what is
30:13:27
the minimum amount of time it takes to reach to any particular node. Then we are going to be adding the very first
30:13:34
value as saying that in order to reach to node K it takes zero amount of time
30:13:39
and this would be the starting point for our min heap or priority cube. Next thing is that we will have to initialize
30:13:46
the distances uh of an array with uh the starting value as maximum value. So we
30:13:52
create a new array starting with n +1 nodes plus we fill out all the values
30:13:57
that we currently have with the maximum value possible and the value at the kth
30:14:02
position in order to reach to kth distance we mark it as zero because it takes zero amount of time to reach to
30:14:08
node number k. Now then our priority q iteration starts that while the priority q is not empty. Number one thing we are
30:14:16
going to do is pop out the very first element that is present inside the priority cube. Mark the current node
30:14:22
with the very first value inside the priority cube and the current distance in order to reach to that node as the
30:14:28
second node of the tpple. Then we are checking that if the current distance is
30:14:34
greater than the current distances that we have already found then which means we can simply ignore that case and we
30:14:41
don't need to iterate do anything with that particular node. But if we don't have calculated or we found some value
30:14:48
that is smaller then we are going to check that what are all the neighbors for that particular node and we are
30:14:55
going to be marking all of those neighbors uh in our graph like data structure and adding those to the
30:15:02
priority cube. On top of it we are going to be updating the distance that we need to calculate uh by adding the current
30:15:09
distance plus the new distance that we found in order to reach to that particular neighbor. So this way we are
30:15:15
continuously updating all the values we can inside our array. Lastly all we need to check is that inside the new maximum
30:15:23
distance array that we have created uh that we need to check that in know in
30:15:28
the given array what is the maximum value we currently have. Notice we are skipping the very first element inside
30:15:34
the node because we are starting from n is equal to one index not zero index.
30:15:40
And then we can simply check that if we found that the maximum distance to be the maximum value possible then we need
30:15:47
to return minus one. If that is not the case then we simply return whatever the maximum distance we found inside the
30:15:52
array. So let's try to run this code. Hopefully it should be working.
30:15:58
Seems like our solution is working as expected. Let's submit this code.
30:16:03
And our code beats almost 70% of all the other solutions which is pretty great and pretty awesome. So once again you
30:16:10
can find the coding solution for this problem in our GitHub repository link is in the description. Take care.
30:16:26
Hello friends, hope you are having a fantastic day today. So now we are going to solve an awesome lead code problem
30:16:31
that has tons of practical use cases. We are going to solve a problem called cheapest flight within KTOPS and all the
30:16:38
travel companies and airlines uses the logic we are going to solve in this problem. So this is a really important
30:16:44
and informative problem with lot of useful properties. So basically in the problem statement we are given n cities
30:16:52
that are connected by some flights and we are given an array called flights
30:16:57
where we have three values. We have the source city. We have the destination city and we have the price it takes to
30:17:04
get from like the source city to the destination city. And we are given bunch of entries like this. Now we are also
30:17:11
given three additional integer called source, destination and K that defines
30:17:17
that we want our travel to start from the source city end at the destination
30:17:22
city and K is the maximum number of stops we can we are allowing ourselves
30:17:28
to take and our aim is to find the cheapest tickets that we can find within
30:17:33
the constraint of given case stops from source to destination and if we can find
30:17:40
the cheapest ticket that's great. We need to return that value. If we cannot find any tickets, then we need to return
30:17:46
minus one. So let's try to understand this problem with a real life example.
30:17:51
So here I have given bunch of different uh values inside our flights array and
30:17:58
we also have three different values called source, destination and K. Now we can see that every single entry inside
30:18:04
this array contains three values and we all know that this defines the source city the destination city and the price
30:18:11
it takes to reach to that particular destination city. Uh we are also being told that we are planning our journey
30:18:18
from source city zero and destination city 3. Now this zero and three can be
30:18:23
replaced by any real life values like New York and Paris, France, New Delhi, you name it. And we are saying that we
30:18:30
want to take at most one stops nothing more than that. And now let's try to see
30:18:36
that what is the amount or what should be the answer in this case. So I have
30:18:41
drawn the whole information that we have provided in this flights array in this
30:18:46
beautiful graph-like description. And now we can see that we are starting our
30:18:52
travel from uh city number zero and we need to reach to destination number three. Now we can see that one route is
30:18:59
that we go from 0 to one and then once we reach to stop number one this would
30:19:04
be our first stop and then from one we can we have to go to three because we
30:19:11
are only allowing ourself to only take just one stop. Now from zero there are no other stops that we can take in order
30:19:18
to reach to three. So this is the only path that we are allowed to take within the given constraint and the cost to
30:19:24
reach to city number three in this case is going to be 100 + 600. So in total 700 and this is what we need to return
30:19:31
as the answer. Now say for an example in the same scenario instead of k being 1
30:19:37
if we are given the value k being two as allowed to be to be given. Now in this
30:19:43
case let's see the scenario. First stop we can take is that from zero we can reach to city number one. This is going
30:19:49
to be our first path. Now from the city number one we have two options. One option is that we reach to city number
30:19:55
three. That gives us the answer that we can reach to the destination within $700.
30:20:01
But the other option is that since we are allowed K to be two, we can take one more intermediate city as a stop and we
30:20:09
decide to take a stop at city number two. Now, in order to reach to city number two, it takes $100 plus $100. So,
30:20:16
$200 to reach to city number two. And from city number two, we also have a direct connection to city number three.
30:20:22
And that is also going to be adding the cost of 200. So, it takes 200 to reach to city number two and plus 200 more to
30:20:30
reach to city number three. So, in total, it's going to be 400. So, in this case, the cheapest flight would be 400
30:20:36
that we can return as part of the answer. if we are given our k to be two.
30:20:41
So this is what we need to return uh in this example. Now the first logic that
30:20:47
comes to our mind is a very simple brute force approach where logic is going to be quite straightforward that we go
30:20:55
through every single possibility of all the nodes that we can visit and all the
30:21:00
edges that we can visit and then try to see that what is going to be the cheapest price to reach to the city
30:21:06
number three. In order to do that, we can actually use the graph based representation of this given input uh
30:21:13
flights array and after converting it into the graph, we can actually do like
30:21:18
breath first search or depth first search from any particular node for all the other subsequent nodes. So we are
30:21:25
iterating over all the possible edges and uh recording the values. We can also use backtracking, recursion, you name it
30:21:32
in order to solve this problem. The thing is uh that solution would be okay
30:21:38
in terms of like coming up with just a solution to have but the thing is think of the real life scenario. We are
30:21:44
dealing with hundreds or millions of cities, flights and costs. So that's not
30:21:50
a scalable solution. We need to find a better approach and that's where a beautiful solution or algorithm that
30:21:57
comes into the picture and that is called Belman Ford algorithm. So now
30:22:03
let's see that how can we utilize this algorithm to solve this problem. So once
30:22:09
again we are going to be using the same example to solve this problem using the Bellman fault algorithm. The logic is
30:22:16
quite straightforward. We are actually going to be focusing on the only thing
30:22:22
that for every single K iteration how much time it takes to reach to any
30:22:28
particular destination city and what is the cost associated with that and in the
30:22:34
end for all the given K entries we will keep on running the same process until
30:22:39
we reach to the end that we are looking for and then if we found any particular
30:22:44
cost for the associated destination city in this case we have value number three then we can return that if that is not
30:22:51
the case then we can return minus one so let's try to understand the logic I'm
30:22:57
suggesting to solve this problem for that we are actually going to be using
30:23:02
some sort of placeholder values where we can store that how much time it took or
30:23:08
how much money it took to reach to any particular destination city for that number one thing we need is to have an
30:23:14
array called cost that defines that in order to reach to any particular destination city what is the cost
30:23:21
associated with this. Now the second layer of complexity in this case is value of K because notice that in our
30:23:29
one of the examples we saw if we only have to make one stop then we come up with the different cost but if we are
30:23:35
allowed to use two stops then we are able to come up with a different stop or different cost. So once again we are
30:23:41
going to be using the same logic and in order to justify the value of K if we in
30:23:47
order apart from using this one we will also have to use a temporary array for
30:23:53
every single value of K. So now let's try to understand the logic I'm suggesting. Um currently I have defined
30:24:00
an array called cost and we are going to be seeing that in order to reach to any particular destination city what is the
30:24:07
cost associated with this one. This is the number one thing and second one is this temporary array would be reset for
30:24:14
every single k value and once we calculate that how much time and effort and money it took to reach to any
30:24:21
particular destination city around any of the k iteration then we are going to be copying this temporary array to this
30:24:28
cost area and repeat the same process for the upcoming subsequent k values. Now in this case let's say that for
30:24:35
first we are going to be calculating that what would be the logic for k is equal to 1 then we will see that what
30:24:41
would be the logic for k is equal to 2. Okay so let's uh stay with me this is going to be pretty interesting to
30:24:47
understand and learn the whole process. Now we don't know that how we can uh
30:24:53
define that whether we have a city cost associated that is cheaper or not. In
30:24:59
order to do that, what I'm suggesting is that initially I put the cost to the maximum value possible and after putting
30:25:06
the cost to the maximum value possible, whenever we find some value that is
30:25:11
smaller than the current value, then we update that value because it it is in our benefit to update that the cost it
30:25:18
takes to reach to that destination city. And now let's start our process. Now we know our source city is zero. So by
30:25:25
default logically in order to reach to city number zero the cost has to be zero
30:25:30
because we are already there that is our source city. So we are going to be checking first of all updating that
30:25:37
value inside our array. So for city number zero currently it takes maximum value to reach to that particular city
30:25:44
but we are going to be defining it as zero. Okay. And now we are starting our process. So we are going to go through
30:25:51
edge by edge for every single array. We are going to be updating the temporary
30:25:56
value for that kith element and then uh temporary array is going to be sw
30:26:02
flipped over to the cost and then we are going to repeat the same process. So currently for the temporary array we are
30:26:08
going to take a copy from the cost for this first iteration. So this is zero
30:26:13
and all of these are max in order to reach to the any particular city. Now
30:26:19
first thing is that in order to reach to city number one it takes us $100. So we
30:26:24
are going to be updating that information that in order to reach to city number one it takes $100. But the
30:26:31
thing is first we are going to check that the source city that we are traveling from that already has some
30:26:39
value and it is not the maximum value because if any particular city has the maximum value that means that that city
30:26:46
is not reachable. So if the source city is not reachable, how can we reach the destination city from that source city?
30:26:52
Now in this case source is zero and destination is one and the price is 100.
30:26:58
So we already know that we can reach to the source city because this value is zero inside the current array. So then
30:27:04
we are going to be updating this one as 100 because it takes $100 to reach to
30:27:10
that particular city. Next thing is in order to reach to city number two it takes $100 from city number one. Well
30:27:17
the thing is in our original cost array we cannot reach to city number one. So
30:27:24
once again for this one we should not be able to reach to city number two as well because city number one is not
30:27:30
reachable. So notice this is going to be for k is equal to one only one city. So
30:27:36
uh we can only make one stop. So that is this stop. And if we so that's it. So
30:27:42
now uh next thing is in order to reach to uh city number zero the cost is 100
30:27:49
from uh source city 2. Once again for two source city 2 we cannot reach inside
30:27:55
the cost array. So we cannot update the update any value and also in this case this would not be updated because
30:28:01
currently in order to reach to city number zero the cost we have is zero and this is 100. So why would we pay higher
30:28:08
money if we already have a lower value? So this would not be used. Next value is
30:28:14
in order to reach to city number three it takes $600. The thing is we cannot
30:28:20
reach to city number one. So currently and notice that the currently we are iterating over k is equal to0 and we
30:28:27
have maximum value of k is equal to 1. So we are going to be running this iteration twice. So currently for k is
30:28:34
equal to0 the this one is from 1 to 3 it takes
30:28:40
$600. Well thing is uh we cannot reach one so we cannot reach three. Once again
30:28:45
next iteration uh we cannot reach any other city because uh 2 to 3 is 200 but
30:28:51
we cannot reach two so we cannot reach three. So these are also going to be blank. Now notice that after the first
30:28:58
iteration we only traveled one city that was the immediate neighbor of this node
30:29:03
number zero. And this is the whole point of this exercise that every iteration we are going in like breath manner for all
30:29:12
the cities that we can iterate over and we are updating the cost accordingly.
30:29:17
Now for the next k iteration we also need to update the value of this temporary value inside our current cost
30:29:24
array. So first we will update this one. So this is going to be 0 100 and then these two are going to be max value and
30:29:30
max value. And once again we are going to be starting with a blank temporary array but we are going to take the copy
30:29:36
of this cost array. So this is also going to be 0 100 and then max value and max value. Now let's see the same
30:29:42
iteration again. Now 0 to 1 100 we already have this value stored. So we don't need to update 1 to 2 100. Now in
30:29:50
this case we are able to reach to city number one with 100 cost. So in order to reach to city number two the cost has to
30:29:56
be 200. So we can update this value to be 200. And notice that this time we are
30:30:02
iterating over for k is equal to 1. We initially started for k is equal to0. And now we are going to keep on
30:30:07
repeating the same process. Now next thing is 2 to 0. It takes 100 but we don't need to update that because in
30:30:14
order to reach to zero we already have the value as zero. Next one is 1 2 3 as 600. Currently in order to reach to one
30:30:20
we have the value 100. So we can reach to city number three and 1 2 3 is going to be 700. So we are going to updating
30:30:27
the value as as 700. And now next thing is u 2 to 3 is 200 but we cannot reach
30:30:35
two in this case because cost array is still showing two as maximum value. So we are not able to reach this one. So we
30:30:42
are not going to be considering this edge. And next thing is next would be the k is equal to two. But the thing is
30:30:48
notice we only have k is equal to 1 as max. So the moment we are done with this
30:30:53
one we will break out of all the loops and sorry before this one uh we are
30:30:58
actually going to updating the temporary array to the cost array as well. So now inside our cost area we will have a
30:31:05
couple of more entries. So in order to reach to city number two it's going to be uh 200 and in order to reach to city
30:31:12
number three it's going to be 700. Now after this one once we end our loop we
30:31:18
are going to be checking our cost array we are going to be seeing that if the destination city is three and if this
30:31:24
value is not maximum then whatever value is we need to return this one. So answer is going to be 700 and if we cannot
30:31:32
return 700 like if the value would have been maximum then we would have written minus one. Now let's see let's take one
30:31:39
more example for k is equal to 2 just to solidify your understanding once again
30:31:44
uh 0 to 1 100 we already have updated this value 1 to 2 100 we also have
30:31:50
updated this value as 200 1 2 to 0 is 1 uh 100 we don't need to update this one
30:31:57
because we have 0 as 0 1 to 3 is 600 so this has also been updated and next
30:32:04
value is 2 to 3 is 200 so This value we can see that we can we are able to reach
30:32:09
to city number two. That means we can reach to city number three. The cost is going to be 200 + 200 400. But the
30:32:16
current maximum cost to reach to that particular city is 700. So we need to
30:32:21
remove 700 with 400 because now we can reach to city number three with 400
30:32:26
cost. And now since this is k is equal to two once we are done with our loop we
30:32:32
will update this value over here. So this becomes uh 400 and then uh in the
30:32:37
end if we have to return the answer we can return 400 that after with k is equal to two stops we can reach to city
30:32:44
number three in 200 cost. So imagine see how beautiful the solution is. And now I
30:32:49
hope you understood that what we are trying to do over here. If we have to calculate the time and space complex complexity, it's quite obvious that for
30:32:57
k times we will have to iterate over all the given uh edges that we currently
30:33:03
have and all the given nodes that we currently have. So it's going to be k multiplied by the number of nodes and
30:33:08
edges. So O multiplied by v. Uh so yeah and this would be the time complexity.
30:33:15
And if we see space complexity, we are using couple of arrays to store the values. This is going to be the
30:33:20
temporary storage and this is going to be the constant storage. But both are dependent on the number of cities. So
30:33:26
let's say if the number of cities are the number of nodes. So it's going to be big of n where n defines the number of
30:33:31
nodes. And this is the whole solution. Now let's quickly see the coding uh solution for this one.
30:33:41
So the coding solution is actually quite straightforward. First we are going to initialize our cost array. Then we are
30:33:47
going to be filling the cost array with the maximum value possible. Then we are going to define that in order to reach
30:33:54
to source city it takes us zero amount. So we are going to mark it as zero. And then we are going to initialize our two
30:34:01
loops. First loop is only going to run from zero to k value where we are going
30:34:06
to be starting a temporary array where that is going to be the clone of our
30:34:11
cost array that we have created so far. Next we are going to be iterating over every single edge. Now for this edge,
30:34:19
first thing we are going to be doing is defining the value of U, V and the cost
30:34:25
to reach to that particular city where U is the source city, V is the destination city and cost defines that how much
30:34:32
money it takes to reach to the destination city, the values are extracted from our flights input array.
30:34:38
Next first thing we are checking is that in the original cost array if in order
30:34:43
to reach to city U that is the source city is maximum value that means we
30:34:48
cannot reach source city in that kth iteration. So we need to do we need to continue oper that operation. If that is
30:34:55
not the case and we are able to reach to the source city then we are checking that in order to reach to the
30:35:02
destination city V what is the current cost we have and if the current cost is
30:35:09
actually greater than the cost we are able to achieve using the cost it takes to reach to city U plus the current cost
30:35:17
for the based on the current edge whichever is the smaller we are going to be keeping that value inside our
30:35:23
temporary array. And once we are done iterating over all the flights for that kith iteration, we
30:35:30
are going to be copying the temporary array inside our cost array and repeat the same process for the next k
30:35:36
iteration. In the end, the answer is quite straightforward. We need we simply need to uh check that if the cost to
30:35:44
reach to that particular destination city if that is the maximum value possible then we need to return minus
30:35:50
one. If that is not the case, whatever the cost value is, we can simply return this one. And this is the whole
30:35:56
solution. Look how beautiful it looks. Now let's try to run the solution.
30:36:03
Seems like it's working as expected. Let's submit this code.
30:36:10
And our code runs beautiful. It beats almost 97% of all the users, which is
30:36:16
pretty awesome. And uh I will be posting this solution inside our GitHub repository. So if you want you can go
30:36:22
ahead and check it out from there. Thank you.
30:36:34
So the lead code problem we are going to solve now is called minimum cost to connect all points. This is a very
30:36:40
popular question in my opinion. Why? because we are going to be dealing with something very important that is called
30:36:45
prince algorithm to solve this problem and this prince algorithm actually has lot of different practical applications
30:36:51
that you can use it in all sorts of different questions and different techniques. So let's understand the
30:36:57
problem statement. We are given an array points that represents an integer coordinates of few points on a 2D plane
30:37:04
which means x and y type of graph and we are told that any particular point value
30:37:10
is defined as x i and yi. So the coordinates of that location now we are
30:37:16
told that the cost of connecting two points x and y is the manhattan
30:37:21
distance. So let's say that if you typically has like three values and if you are trying to let's say connect any
30:37:28
two like this one in this case the cost of this one is going to be the pythagoras if we try to choose the
30:37:33
diagonal but the thing is Manhattan distance is that instead of picking out the value of the straight diagonal
30:37:40
between these two points you first go to a common point and then go to right. So in this case you are actually doing the
30:37:47
delta of x and you are also doing the delta of y. So absolute values of x1 and
30:37:52
x2 amongst these two points and the sum of this is going to be the total distance you are going to cover. So this
30:37:59
is called manhattan distance and this is what we are going to follow. So it's slightly better for us so that we don't
30:38:05
have to spend so much time on calculating the pythagoras or root values. Now we need to return the
30:38:11
minimum cost to make all the points connected. Now let's try to understand this with an example. In this case,
30:38:18
suppose these are the different points we are given. Now, we need to make sure that number one, we connect all of these
30:38:25
points in some fashion. And after connecting these points, we also need to make sure that the distance we are
30:38:31
traveling by connecting them is the minimum distance we can. Now, let's try
30:38:36
to understand first of all that how does a Manhattan distance is going to work. So, let's say you want to find out that
30:38:42
what is going to be the distance between these two points. Then, logic is going to be quite straightforward. You are
30:38:47
first going to do the difference between X pointers. So this sorry Y pointers and you are going to add it to the
30:38:53
difference between X pointers. So in this case the distance between these two nodes is going to be four. And though
30:39:00
it's not a diagonal I'm just writing it diagonally so it becomes easier for us to understand. Now the thing is the
30:39:06
solution of this problem is something where we will have to deal with minimum
30:39:11
spanning tree. Now minimum spanning tree is a very important concept in the graph theory where you are given bunch of
30:39:19
different points on any particular plane and you are trying to connect all of these points in some fashion such that
30:39:25
the there there are no cycles being formed and you are not you are trying to
30:39:31
span the tree in like only the places where it is absolutely needed nothing more than that. Well, the question is
30:39:38
the first thing that should come to your mind is that hey in this case we are only given points. We are not given the
30:39:44
edges which means these are simply just the nodes we are given. We know in order
30:39:49
to solve any particular graph pro problem we need two items. We need a nodes and we also need edges. But the
30:39:56
thing is good thing for us is we we already know how to calculate edge between any two points. And the thing is
30:40:02
in this case there is possibility that from every single point you are able to
30:40:08
connect to every other point in order to treat it like an edge. The thing is uh
30:40:13
if I try to draw the whole solution by that matter, it's going to look very bad
30:40:19
because imagine how many number of different edges you can form amongst all of these points and then it it is only
30:40:26
going to look so much more messy and complex if you have to understand all the different flows and data entries and
30:40:32
data points and whatnot. So what we will try to do is we will understand that what is the most simplest logic we can
30:40:39
use to solve this problem and we will also understand that how we are going to
30:40:44
be using the prim's algorithm and the solution of basically prim's algorithm
30:40:51
plus the graph theory concept to solve this problem. So let's start working on
30:40:56
the solution of the problem. I I hope you must have understood that what the problem is asking us to solve. So now
30:41:02
let's very quickly and very simply think one by one that what are all the
30:41:08
different possibilities we have across all of these five different points. Well number one possibility is that if we are
30:41:15
at this point we don't know that what are all the points that are currently present inside the remaining graph.
30:41:22
Which means we don't know that if we have to generate a minimum spanning tree that crosses or that goes through all
30:41:28
every single nodes that are currently present which node should this node zero
30:41:34
be connected to. So we don't know this question number one thing that what is the minimum cost to reach to any
30:41:41
particular point from this node zero and remember we need to make sure that we don't form any cycles because we simply
30:41:48
need to connect all the points and if there are cycles basically we our cost
30:41:54
of connecting all the points would increase. So the shortest way to connect all the points is to is through like
30:42:00
some sort of a straight line or a tree kind of structure where there are no cycles. So now at this zero the number
30:42:07
one thing we will have to do if we have to fi find the shortest distance or the closest point we will first have to
30:42:13
calculate every single distance we can from all the remaining points to this
30:42:19
zero node and the distance between these points would be treated as the edges
30:42:25
because we are basically connecting two different points and amongst those edges we will have to find the edge with the
30:42:32
smallest value. So these are actually weighted edges. And the other thing is
30:42:38
the connection in this case is going to be birectional. Why? Because whatever the distance from this zero to this node
30:42:44
is same distance is going to be from this node to zero as well. So we don't need to do any directed distance
30:42:50
calculation in this matter. All we are concerned about is unidirectional uh
30:42:55
transfer and to understand that what is the minimum place to reach that place. Now comes another problem. Let's say
30:43:02
that from the zero it makes logical sense that this is going to be the smallest distance that we can calculate
30:43:08
and we also know that the distance amongst this one is going to be two. So sorry 2 + 2. So total let's say that
30:43:14
this distance is four that we already know that this is going to be the smallest distance. But once again when
30:43:20
we come back to this place now we still have three more nodes that we will have to iterate over. We are not not going to
30:43:26
iterate over node number zero. We are going to treat that this zero has already been visited. But once again we
30:43:31
will have to repeat the same operation. And from this po position we know that the shortest distance we should be able
30:43:38
to find is going to be this value. So if we calculate this I think this distance is going to be three. Okay. And same way
30:43:46
from this three the shortest distance that we calculate for any particular node is going to be this one. And this
30:43:51
distance is also going to be four. But the thing is now we still have one more node remaining and we already found the
30:43:59
results for these four different nodes. So question is how do we know that which
30:44:04
node is actually going to call to this particular node. So for that we will actually have to find a way that while
30:44:11
we are calculating the distance from zero node to all the other nodes and same way from this first node to all the
30:44:18
other nodes we will still have to keep track of all the nodes that are that are
30:44:24
still remaining because the thing is it could be possible that there are some nodes that are not down the path of the
30:44:30
shortest nodes but the thing is we need to connect all the points. So we will still have to find a node that is still
30:44:37
closest to this node that it makes sense to make that connection. Now I know what I just said might sound confusing but
30:44:44
the thing is try to understand this from an example point of view that if you are
30:44:50
all only if we only traversed or if we only use the greedy approach where we
30:44:55
are just iterating in the minimum fashion then we are always going to be stuck with one node that is not
30:45:02
following that this beautiful path and the thing is if we try to find the path to that node that remaining node from
30:45:09
here this might be much longer compared to this distance. So in order to do that
30:45:14
the what logical solution I'm suggesting is that at we first start at the zero
30:45:19
position. From the zero position we make the calculation that how much time it is going to take to travel to this first
30:45:26
node, second node, third node, fourth node, all of these nodes. Same way then
30:45:31
we find that amongst these four nodes which one has the smallest value to reach to there. So smallest edge and we
30:45:38
realize that the smallest edge is one in this case. Then from this one we know that we already calculated the distance
30:45:45
for for zero. One is a self node in its own which means now from one we will
30:45:50
have to keep track that how much time it takes to reach to node number four 2 and
30:45:55
three and keep all of these results stored somewhere as well and then try to pick the smallest value that we can.
30:46:03
Once again from the smallest value repeat the same operation for the remaining elements. So even from this
30:46:08
smallest value we will calculate these two distances. Once again pick the smallest one and then from the smallest
30:46:15
one see that what is the remaining value and for all the remaining values. So for
30:46:20
this remaining node see that uh currently we should have three results. One result is between node one and this
30:46:27
one node number four. Second result is node two and node number four. And third result is node three and node number
30:46:33
four. And amongst these three whichever is the smallest one pick that one and that would be our solution. So now let's
30:46:40
just try to walk through the whole solution that we just talked about and see that what are all the different
30:46:46
concepts we will have to use to complete the solution in a manner that we are proposing. Now first of all what we need
30:46:53
to do is we will need to make sure that there are no cycles. In order to make sure that we will have to keep track
30:46:59
that all the nodes that we have currently visited. So we can use some data structure like a hash set or an
30:47:04
array or a boolean array of size n to keep track of all the values that we
30:47:09
have visited so far. So let's say we will use hash set for now for our understanding purposes. But at the same
30:47:16
time we are also going to be using array during the implementation. Okay. So let's say that we currently have our
30:47:22
hashet that we are going to be storing to make sure that there are no cycles.
30:47:27
Next thing is we will have to make sure that for every single node we calculate
30:47:32
the distance to all the remaining nodes find their distance and we need to sort
30:47:38
those distances. So in order to do that one of the beautiful data structure we
30:47:43
have is actually a heap and we can have a min heap where from every single node
30:47:49
that we start iterating over for all the remaining values we will try to calculate the distance and put them in
30:47:54
the main heap so that we it would be stored in like from uh in uh ascending
30:48:00
order. So smallest value would be at the beginning that we should be able to find and how we are going to be storing the
30:48:06
value inside the heap would be in this fashion where the first value is going to be the distance and second value
30:48:11
would be the point. So we would say that in order to reach to that particular point what is the smallest distance that
30:48:17
we will have to cover. That's it. That's all we need because we are only concerned about the cost to reach to
30:48:22
that point. So now let's see that first node is zero. In order to reach to zero and let's say that we decide to start
30:48:28
from zero. It's not necessary that we have to start from zero. But let's say that we decide to start from zero. So in
30:48:33
order to reach to zero, what is the minimum cost it takes? So minimum cost it takes is still going to be zero. So
30:48:40
we are going to be adding the value 0 0 over here. Next thing is from zero. Now we have four different options to choose
30:48:46
from that in order to reach to all of these values. So first value is in order to reach to let's say this one is node
30:48:53
number one, node number two, node number three and node number four. So in order to reach to node number one the smallest
30:48:58
distance it's going to take is going to be value number four and we will mark it as by by 4 1. Same way if we have to
30:49:06
reach to this value number three let's say that the distance is going to be 5 + 2 7. So we can mark the values as 7 and
30:49:13
3. Same way if we have to reach to this value number two then the distance is going to be 13. So we can mark 13 and
30:49:20
two. And next thing is uh same way if you have to reach to value number four then the distance is going to be seven.
30:49:26
So we can still mark 7 and four. And notice that we are going to be sorting these values because this is a min heap.
30:49:32
So it would automatically be sorted. So the value would be uh something like this one. So 7 and 4 and then I think it
30:49:40
was yeah 13 and two. So these are the currently four values that or five
30:49:45
values we have so far. We will pop and now we have started our iteration. So we
30:49:51
will pop the very first element which means we pop this value 0 0 and we know that the cost to reach to value number
30:49:56
zero is zero. So we will also need to have a variable to store all the cost. So let's say that we have a variable
30:50:03
that where we are storing all the cost. In the cost we first add zero because that is the cost to reach to value
30:50:08
number zero. Let's say we kick out value number zero. The thing is because we already visited zero we are also going
30:50:14
to be marking zero inside our hash set. So let's say that this is our hash set and we already visited node number zero.
30:50:21
So from now on any subsequent entries that come in with value number zero we are simply going to ignore that because
30:50:27
we have already visited that inside our hash set. Okay. And uh let's uh keep on
30:50:33
doing the iteration. Now the next entry inside our heap is node number one. From
30:50:39
node number one it takes four cost to reach to node number one. So let's mark the cost to 0 + 4. We are also going to
30:50:46
be marking that one has already been visited so far and we have this this channel being established. Okay. Now
30:50:54
from once again from one we will have to repeat the same operation because remember from every single node what we
30:51:00
are trying to do is we are going out in the breath first search manner not depth first search manner. So we went to one
30:51:07
of the neighbors of four and then we are going to be visiting one of the neighbors of one. Same way we are going to be visiting one of the neighbors of
30:51:13
three and same way we are going to be visiting one of the neighbors of four. So this is a BFS traversal not a DFS
30:51:19
traversal and uh now let's just mark one and uh okay so now once again we are
30:51:26
going to leave all we are going to be popping these two entries but these three entries like 73 74 and 132 is
30:51:34
still going to be present inside our heap. Now from this one we have once again three options. First option is
30:51:40
this one. The cost of this is nine. Second option is this one. The cost of this one is three. And the third option
30:51:46
is from 1 to four. So the cost is going to be uh 2 and five. So 7. So once again
30:51:53
we are going to be having one entry that is three and three which is in order to
30:51:58
reach to node number three we are going to be using distance three. Next entry is uh in order to reach to node number
30:52:06
four the distance is going to be seven. So next entry would be 74. So we can also put one more entry over here 74.
30:52:13
Okay. And uh we are going to be having one more entry that is 92. In order to reach to two the distance is going to be
30:52:20
9. So we will have one more entry 92 over here. And then the 132 would be
30:52:26
like subsided to the back end. And uh this is going to be the current values
30:52:31
inside our min heap. Now once again we are going to be pop popping out the very
30:52:37
first element that is the smallest element that is node number three and in order to reach to node number three we
30:52:42
will have to add cost as plus three. So we will mark plus three cost over here
30:52:48
we will mark three as being visited because we already visited this one and we will get rid of this entry. So now
30:52:54
you can see that now the moment let's say that uh suppose I'm just giving you for an example suppose we say that this
30:53:01
is the next closest node and we will try to extract this one. The moment we see that in order to reach to node number
30:53:06
three it takes seven costs. The thing is we already visited three inside because it's present inside the hash set. So we
30:53:12
can simply ignore this case and same way we are going to be ignoring all the cases that are going to be uh like
30:53:19
different from uh the nodes that we have not visited so far. Same way from three
30:53:24
to four we we have uh this type of distance and that distance to four is
30:53:29
going to be four once again. So we can mark 4 because that is the smallest entry and from three we will have to
30:53:35
calculate one more distance that is to up to this two and that distance is going to be uh 10 2. So we can mark one
30:53:41
entry over here that is going to be 10 two but so once again we are going to be adding cost four because we visited node
30:53:48
four. It takes four unit of time to reach to node number four and we visited
30:53:53
all of these entries. Now the thing is we visited all of these. Now um from
30:53:59
four we will once again calculate the distance to two. So let's say that this distance is going to be 15. So 15 to
30:54:05
two. So currently these are all the entries we have inside our heap. And
30:54:10
let's see that what what we need to do. So we already visited 0 1 3 and four. We
30:54:16
haven't visited node number two. So we start popping values out. So we first pop this value 7 74 because we have
30:54:23
visited four. So we can just ignore this one. Same way we can just ignore the 74 and then we have this node 92. So we pop
30:54:31
92 out. Two we haven't processed. So we are going to be marking the node two visited over here. And add this cost 9
30:54:38
over here as well. And now you can see that uh the size of our hash set is exactly same as the size of all the
30:54:45
number of points that we are given which means we have visited all the nodes and we can stop our conclusion. So in order
30:54:51
to do this one the moment we the size of our hashet becomes the the number of
30:54:57
nodes present we can stop our calculation and whatever the cost we found so far we can return that as the
30:55:03
answer. So in this case the answer is going to be 20 and this is the whole solution. So I hope it makes sense to
30:55:10
you that how did you how did we calculated this or we dealt with lot of concepts that that how not to detect
30:55:17
cycles. Uh then we also make sure that we had a hash set to understand that
30:55:23
what are the nodes visited so far. We had a heap to find the smallest entry
30:55:28
from any particular point and we were doing all of this while calculating the cost of the minimum spanning tree. So
30:55:34
this is a beautiful solution. If we understand the time and space complexity, time complexity is going to
30:55:40
be bigo of first of all let's imagine we will have to do n square work for any single node. Why? Because at this
30:55:46
position we will have to calculate distance between all of these four points. Same way at this particular location we will have to calculate the
30:55:52
distance between all of these four points. So we will have to do bigo of n square work to calculate all the
30:55:57
distance and then we will have to find the shortest distance and shortest distance we are finding by using a heap.
30:56:03
So it takes n login time in order to find the solution from the heap. So
30:56:08
overall the time complexity is going to be big of n² login. If we see space complexity because we are storing all
30:56:15
the entries inside our heap it is also going to be big of n square. So overall this is an expensive time in space
30:56:20
complexity but given the scope of problem we cannot do anything better than this one. So now let's quickly see
30:56:27
the coding solution. So the very first thing we are going to do is to define the total length of
30:56:32
given all the points that we currently have. This we are going to be using to check against that whether we have
30:56:37
collected all the points or not. Then we are going to be initializing our priority Q and this is going to be our
30:56:44
min heap. Then we are also initializing a new boolean array to store the all the
30:56:49
values that we have currently visited so far. So we are marking it as in MST whether it is present in the in the
30:56:55
minimum spanning tree or not. Then we are defining a new class called point.
30:57:01
So let's understand this one. So we have a new class called point and it only contains two values. First one is a
30:57:06
distance and second one is an index. And we can see that we are going to be using this uh instance of this class to store
30:57:14
values inside our min heap where we are storing that in order to reach to any particular index what is the distance
30:57:20
that it takes and then heap would sort it out for us. And the very first element we are adding inside the heap is
30:57:27
that we are adding the very first value the or value located at index position
30:57:32
number zero inside the points and we are saying that it takes zero cost to reach
30:57:38
to those points and this is how our priority Q works. We are also having a variable to store the minimum cost um
30:57:45
that we have been able to find so far. And we have a value called points connected. So which we can use it to
30:57:51
compare it against the total given length of points to define that whether we should complete our iteration or not.
30:57:58
Then we are running our loop until our points connected reaches to the total
30:58:03
number of n that is currently present. Then we are fetching the very first value that we currently have uh out of
30:58:11
the priority cube. So we are doing a pole operation and then checking that whether this point that we found out uh
30:58:18
this current point have we already visited that current point. So we can check that using uh the boolean array
30:58:25
that we have created. Then we are checking that if we have not visited then we are going to be marking it as v
30:58:31
visited and we are also going to be updating the minimum cost to reach to all the nodes by the distance that it
30:58:38
takes to reach to that particular node and we are also updating the value of points connected so far. So now we
30:58:45
already calculated and visited that particular point but the thing is we will have to still calculate the distance to all the remaining points
30:58:52
from that point. So we are going to be running another for loop that is going to span across every single uh n that is
30:58:59
currently present. First we are checking that any particular index that we are checking have we already visited or not.
30:59:05
If we have already visited that that we then we can ignore. If we have not visited we will calculate the distance
30:59:11
by using the map the math.absolute absolute points and then uh we will add
30:59:17
a new entry inside our priority Q by adding that E location and the distance
30:59:23
to reach to that I location and it would sort it automatically. In the end, we simply need to return the min cost that
30:59:29
has occurred so far to reach or connect all the points and this is the whole solution. So let's try to run our code.
30:59:40
Okay, seems like our solution is working as expected. Let's submit this code
30:59:46
and our code runs beautifully compared to a lot of other solutions. It's almost 80% faster in terms of time complexity
30:59:53
and also 80% faster in terms of space complexity. So which is pretty great. Once again the solution is present
30:59:59
inside our GitHub repository. So feel free to go ahead and check it out from there. Thank you.
31:00:13
So once again we are going to do a very awesome lead code problem. This one is a rec construct itinary. We can see that
31:00:20
this one is a lead code hard problem. Also constructing an itinary is actually a very popular real life use case that
31:00:27
we see in like uh aviation industry all the time. So this is an important problem. Let's pay our utmost attention.
31:00:34
Now we are given a list of airline tickets where any particular position uh
31:00:40
we are given like a tpple value inside the array that defines that where what
31:00:46
is the departure and arrival for locations based on that particular unit.
31:00:51
Now we need to reconstruct the itinary in in like a particular order and return
31:00:57
that reconstructed itonary. Now let's see that what are the constraints around reconstructing the itinary. Number one
31:01:04
thing is all the tickets belong to a man who departs from JFK which means JFK is
31:01:10
the starting position for our entire itenary. Then uh next thing is that if
31:01:16
there are multiple valid itonaries that we are able to construct then we should
31:01:22
return the itonary that has the smallest lexographical order. So what does
31:01:27
lexical lexographical or lexical order means? It means that uh we need to sort
31:01:33
them in like a toz manner basically. Uh which means uh if we let's say if we
31:01:39
have two tickets first one is from JFK to LGA and second one is another ticket
31:01:45
from JFK to LGB then we must return LGA first before returning LGB because
31:01:52
remember that we are sorting lexographically. So this one has character A and this one has character
31:01:59
B. So a comes before b which means this has a smaller lexical order. So we need to uh put this in priority. Now we are
31:02:07
also told that we may assume that all the tickets are valid and we must use
31:02:12
all the ticket once and only once. So let's try to understand this problem uh
31:02:18
and try to see that what could be the potential solutions. Number one thing is this is the type of input we are given.
31:02:25
Now we can see that there are bunch of different tickets we are given. In this case, we are given a ticket that uh is
31:02:30
from Munich to London Heathro. We are given a ticket from JFK to Munich. Then San Francisco to San Jose and London
31:02:37
Heathro to San Francisco. So these are the five tickets we are currently given. I have just plotted all the five
31:02:43
airports I over here. And now let's see that what is the solutions we can make. So let let's just take a simple approach
31:02:50
and uh let me just keep on marking all of these nodes or like all the flight
31:02:56
connections. So we know that we have a connection between Munich and London Heathro. So let me mark this one. Then
31:03:02
we have a connection from JFK to Munich. So let me also mark this one. Then we have a San Francisco to San Jose. So
31:03:08
marking this one. And then we have London Heathro to San Francisco. So let's mark this one. So this is a valid
31:03:15
order. We can see that every single ticket we currently have that are four tickets. We have we used all of these
31:03:22
four tickets over here. After using all of these four tickets, we need to reconstruct itonary starting from JFK.
31:03:28
So we can see that if we start our journey from JFK, the direction is going to be JFK to Munich, then Munich to
31:03:34
London, Heathrow, Heathrow to San Francisco, and San Francisco to San Jose. This is the reconstructed itonary
31:03:41
that we need to return in this order. Let's take one more slightly complicated scenario. So we have uh like bunch of
31:03:48
different tickets in this case and we only have three airports to deal with. So first ticket is JFK to San Francisco.
31:03:56
So let's just mark this one. So JFK to San Francisco. This is one option. Second option is JFK to Atlanta. So
31:04:03
let's mark this one. Then San Francisco to Atlanta. Okay. Then Atlanta to JFK.
31:04:09
Okay. And then Atlanta to San Francisco. Okay. So currently these are all the
31:04:16
different options we have. Now let's see that what is the optimal option we need to choose. We need we know that we need
31:04:22
to start our journey from JFK. Now notice at JFK we have two different tickets going outwards. First ticket is
31:04:28
going to the San Francisco and second ticket is going to the Atlanta. So question is which ticket should we
31:04:33
choose? Now here comes the lexographical ordering that we need to pick from and we can see that Atlanta is
31:04:41
lexographically smaller than San Francisco. So we are going to pick ATL first. So in our path this is going to
31:04:48
be the first path we are going to take. All the markings that I'm marking with red is like the correct marking. Okay.
31:04:55
So we took care of one ticket. Then from Atlanta once again we have two options. We can either go to JFK or we can either
31:05:03
go to San Francisco. So once again it makes sense to pick the smaller amount
31:05:08
and that is once again going back to JFK. So let me let us go back to the JFK. Now at JFK we only have one option
31:05:15
that is go to San Francisco. So we go to San Francisco and then from San Francisco now we only have one option
31:05:22
and that is to go to Atlanta. So we go to Atlanta and now from Atlanta we still have one more edge that is remaining and
31:05:29
that is to go back to the San Francisco. So we will once again go back to the San Francisco. So this is the sequence we
31:05:34
are going to follow where first we are going to go from JFK to Atlanta then
31:05:40
this is the second this is the third this is the fourth and this is the fifth flight we are going to take. So this is
31:05:45
what we need to return. Now I know understanding this question took way longer than expected but don't worry the
31:05:52
solution is not that complicated. So let's just try to understand a simple
31:05:57
logical scenario just for this particular input that we are given. What
31:06:02
is the one thing that we did to solve this problem? Well, it is quite obvious what we did to solve this problem. We
31:06:09
first of all mark that from every single airport what are all the different
31:06:14
possibilities we can take and then we started iterating over our journey from
31:06:19
JFK on top of it not only marking the all the different possible journeys we
31:06:25
also mark that what uh under what order should we start picking uh and start
31:06:32
moving in in any particular direction so what I'm suggesting in this case is that
31:06:37
we are only given the tickets we are only given these values from any particular two nodes what I'm suggesting
31:06:43
is that we actually treat this as a graph problem and which is pretty obvious why are we treating it as a
31:06:49
graph problem through this one we are going to be marking every single airports we currently have as the nodes
31:06:57
and all the tickets that we currently have as the edges okay we already got our nodes and edges on top of it what we
31:07:05
need to do is we need to iterate over the given graph graph. Now, iteration of the graph is quite simple. We know that
31:07:11
we have two methods. We have a breath first search method and we have depth first search method. Now, in this case,
31:07:16
going in one particular direction makes more sense because notice that over here we are going in like a depth first
31:07:24
search fashion. Even in this example, we saw that we were doing bunch of different back and forth in order to
31:07:30
complete all of our transaction. And that was also being done in depth first search fashion. So in this case we are
31:07:36
also going to be using DFS to iterate over all the nodes. Next thing is we
31:07:41
need a starting pointer to iterate over. We already have a starting pointer and that is starting from the JFK. So we
31:07:47
know that we first of all need to treat it as a graph. We will need to do a DFS.
31:07:53
We will need to start iterating over from JFK. Next thing is when we are constructing a graph we will have to set
31:07:59
up ordering in which sequence are we going to go to any particular airport and for that we will have to follow the
31:08:06
lexical graphical ordering. So for that what I'm suggesting is that we actually use an adjacency list kind of a scenario
31:08:13
where we store the adjacency list for our graph or and we do it in
31:08:20
lexographical ordering. So what I'm suggesting is that we initialize a hashmap as part of the hashmap we need
31:08:26
two items key and value as part of the key we mark the nodes or the airport as
31:08:31
part of its values we mark that from that airport how many different tickets
31:08:37
that we can traverse over so or how many different airports or destinations we have. Okay. Uh then once we have these
31:08:45
two values then we need to populate these arrays. So let's start populating this value uh for this given input.
31:08:52
Okay. So currently let's go one by one in these u throughout all of these
31:08:57
tickets. So first one is we are starting from JFK. So one node is JFK. Okay. Now
31:09:03
from the JFK we need to have a ticket. Uh the destination is San Francisco. So
31:09:09
let me mark this as SF. Then we have one more ticket from JFK and the destination
31:09:14
is Atlanta. Now we know that JFK is already present. The thing is we are trying to insert Atlanta over here. So
31:09:21
one logical thing is that rather than just doing anything let me just create a link list over here where I'm storing
31:09:28
Atlanta as well that from JFK I have one more ticket that goes to Atlanta. Okay. Same way we have a San Francisco and the
31:09:36
destination is Atlanta. So let me also do that and we have Atlanta and JFK. So Atlanta and JFK. Okay. And last one is
31:09:45
Atlanta to San Francisco. So we are going to have one more destination San Francisco from Atlanta. Now we have our
31:09:51
uh key or our graph uh like uh our adjacy list being created okay inside
31:09:58
our hashmap. But the thing is we need to sort this in lexigo graphical manner. So
31:10:03
what we are going to do an intermediate step where we are simply going to update this given uh graph that we have created
31:10:10
so far. And for this one we are simply going to sort all the values or all the
31:10:16
inputs we have in the destination in lexographical manner. We know that this can be done in n login time. So we are
31:10:23
going to spend that extra time in order to complete that. So let me just start marking this one. So first entry is JFK.
31:10:29
Okay for JFK we currently have two values. First one is San Francisco and second one is Atlanta. But this is not
31:10:34
sorted correctly. So we are going to sort it. First one is going to be Atlanta and second one is going to be
31:10:40
San Francisco. as this is going to be the sequence of link list for San Francisco we only have Atlanta so let
31:10:45
let's just mark this one and the last one even for the Atlanta we have JFK and San Francisco that is already sorted in
31:10:52
correct order so let's just mark this one uh so JFK and we have uh Atlanta
31:10:59
okay uh sorry uh San Francisco okay so let's just mark this one as well and now
31:11:06
we have everything we are looking for now all we need to do is just do the DFS operation from our adjacy list on the
31:11:14
graph and every time we update we iterate over one destination we are going to remove that from the list. So
31:11:20
next time when we are at the same airport we simply pick the next uh next lexographical entry in sequence. So
31:11:28
let's try to run the solution. So we start our uh journey from JFK. So we are
31:11:33
initially at this JFK location. We saw that the first ticket we need to find or first flight is Atlanta. So let let's
31:11:40
just traverse to Atlanta marked as a. Now we need to do the we need to go to
31:11:46
the Atlanta because we are currently presented in Atlanta also at the same time we are going to remove Atlanta from
31:11:52
here and we need we are going to go to the Atlanta. Now Atlanta the very first flight is JFK. So once again we are
31:11:58
going to come back to JFK. So after coming back we are going to remove JFK from here. So now at the JFK the next
31:12:04
flight in sequence is San Francisco. So let's just make one another journey to San Francisco. And uh now we are going
31:12:12
to remove San Francisco from here. Now at San Francisco, next flight is Atlanta. So let's just mark a journey to
31:12:19
Atlanta. And we are going to remove Atlanta from here. And now from the Atlanta, let's just mark one journey to
31:12:24
the San Francisco. So we are going to mark a journey to the San Francisco and we are going to remove San Francisco
31:12:30
over here. Now the moment we uh come to any particular position, let's say we came to San Francisco. Now there are no
31:12:36
more entries or no more destinations for us to visit which means we can conclude that we have iterated over every single
31:12:42
possible tickets that we currently have present and we can simply say that we iterated over all the entries and this
31:12:49
is the path that we created we can just keep track of the path in like a backtracking function and because we are
31:12:56
making recursive calls to use the DFS and solve this problem quite easily quite beautifully quite simply and this
31:13:02
is an awesome lead code problem if we understand the time complexity In this case that that that is going to be big
31:13:07
of vertices multiplied by edges plus big of n login in order to do the sorting
31:13:13
but this is already greater than n login. So we don't need to factor that in. And if we talk about the space
31:13:19
complexity it is going to be bigo of once again ver uh vertices
31:13:25
multiplied by edges because we are creating a new hashmap that is going to be of length v. So actually this is only
31:13:32
going to be big of size V but in the value section we are going to have all
31:13:37
the uh all the edges that we currently have. So it's going to be V plus E. Okay. So this is a still a good time in
31:13:43
space complexity. Now quickly see let's quickly see the coding solution for this one. Okay. So the very first thing we are
31:13:50
going to do is to create a map to store the list of destination for every single departure airport. So we are going to
31:13:56
create a new hashmap where as a key we are going to store the string that is going to store the name of the airport
31:14:02
and as part of its value we are going to be storing a link list or list of strings. Now we are going to iterate
31:14:08
over every single tickets that we currently have and keep on marking all the values uh inside our graph hashmap
31:14:15
that we have just created. After having a representation now we are going to be sorting all the values that we have in
31:14:22
the destination of the graph. So we are going to do run a for loop and just do a
31:14:27
sort operation. After sorting it out, we simply need to start our journey from
31:14:33
the JFK terminal. So we are going to have a link list that is going to be
31:14:38
creating an itinary that we need to return as part of the answer. And we are going to have a DFS operation that is
31:14:45
going to start from the JFK airport where we are going to pass in the graph that we have just created that contains
31:14:51
all the sorted destinations and the itinary link list where we are going to be storing all the values in sequence.
31:14:57
Now let's see our DFS method. So first thing we are doing is that we are adding
31:15:02
the current airport we are at at the uh destination. After that we are checking
31:15:09
that while the given destination is not null and the list of destination is not
31:15:14
empty then we are going to remove that destination to avoid revisiting the same path. So we so we are simply going to
31:15:20
removing that inside our uh array and we are also going to be calling the next
31:15:26
value that we need to iterate over and calling our DFS function once again. So
31:15:31
that's it. This is the whole solution where instead of passing in JFK we are passing in the next airport that we have
31:15:37
to iterate over and we are also adding the airport to our itinary as well just so that we can we know that what airport
31:15:44
we are beginning at and we are generating the itinary in the reverse order. So now let's try to run this
31:15:50
code. Seems like our solution is working as
31:15:56
expected. Let's update this code and our code runs beautifully compared
31:16:02
to like almost 75% of all the other solutions like 71%. It can still be
31:16:07
improved in terms of space complexity. Uh so let me know in the comments if you want to see that. But anyways, you can
31:16:14
still see or find the solution on our GitHub repository. So feel free to check it out from there. Thank you.
31:16:27
Hello friends, we are still not employed by a fang company. So let's not stop late coding till we get there. Today we are going to do alien dictionary lead
31:16:33
code problem. And not only it is a very important problem, this problem can actually be asked in multiple ways. It
31:16:40
can it can be asked directly as a graph question or it can be asked as a follow-up question for the previous uh
31:16:46
question that we solved verifying an alien dictionary because both questions are very similar. And if you want to
31:16:52
check that where the solution for this problem is, you can check it out from over here. Also the another reason why
31:16:58
this problem is really important is if you just take a list of companies that have asked this problem. Airbnb,
31:17:03
Facebook, Google, Amazon, Bloomberg, Microsoft, Uber, they have all asked this question in last 6 months. Also, IT
31:17:10
giants like Pinterest, Apple, Twitter, eBay, they all have asked this question in last 6 months to one year. and uh
31:17:16
bite dance uh Snapchat and Flipkart. So they have asked this question not fairly
31:17:22
recently but still it's important and uh I will be paying my utmost attention
31:17:27
because my aim is to clear any fang interview and uh I hope you also enjoy
31:17:32
the video. This is a lead code hard problem and it justifies this hard tag. Uh so let's
31:17:40
understand the problem statement. Essentially we have identified a new alien language that uses English
31:17:45
alphabet. However, the order of those letters is unknown to us. Now we are
31:17:52
given a list of strings uh inside this words and we are told that they are from
31:17:58
this alien languages dictionary and in that string the important property this
31:18:04
words have is that they are sorted lexographically and we need to return a string of unique
31:18:11
letters that are present in the in these words and we need to return them in
31:18:17
lexographically increasing order. Now also there could be possible that there
31:18:22
might be multiple solutions. So if there are multiple solutions we only need to return any one of them and there could
31:18:28
be some some cases where this given uh string of words is invalid and if it is
31:18:33
invalid we need to return an empty string. So in order to understand this problem first of all we will have to
31:18:39
identify that what does this lexographically increasing order means.
31:18:44
The second thing we will have to understand is that what are the cases where this particular uh input is going
31:18:51
to be uh resulting in falsified uh information and what does this string of
31:18:57
unique letters with lexographically increasing order means because this unique word is actually really important
31:19:05
and uh I'll come to that later. So suppose if we just talk about uh what is
31:19:10
lexographically sorted means if we talk about English language if we talk about the words ab a b c d uh all the way up
31:19:18
to z this is plain English language that we use on a day-to-day basis. Now in the English suppose we are given any four
31:19:25
letters. Uh suppose we are given letters like uh Q A uh E B R C and uh Q E.
31:19:35
Suppose we are given letters like this. Right? And if we want to sort these four in plain English language, how we are
31:19:42
going to sort them? Like of course the answer is simple. We are only going to check that what is their position in
31:19:47
this given order and based on that particular order we will sort them. So if we sort them uh the sorted result
31:19:54
would look something like E A Q A QE and
31:20:00
RC something like this right and the reason we are able to generate this is
31:20:05
because we know that the position of E comes before Q and in this case there
31:20:10
are two entries Q A and QE. So which means like if we will have to identify that what is the second letter and
31:20:17
second letter A comes before E and then this R actually comes before Q.
31:20:25
So we are able to determine a sequence like this. Now in this given problem we don't
31:20:32
need to generate a sequence like this. Uh basically we are told that we are not given this information. We don't know
31:20:38
that what is the order of words are and we are directly given this particular
31:20:43
sequence that is already sorted in that particular language. So suppose this was to be alien language and if you we want
31:20:51
to identify that what should be the answer we need to return in this case. The few things we can determine from
31:20:57
this input is that okay over here the we are checking first uh at any point we
31:21:04
are checking any two adjacent words. In those two adjacent words, we go letter
31:21:09
by letter and we try to see that what is the first differing letter that comes to
31:21:15
uh in comes to the existence and based on the differing letter whatever the
31:21:21
word is presented first should come first in that order rather than second
31:21:27
uh word second letter. Uh so if we compare these two words E A and Q A we
31:21:33
can see that the first differing word comes as E and over here it is Q. So which means we can determine that E will
31:21:40
always come before Q in this particular alien language. Now don't forget this that this is plain English for just
31:21:46
imagine this is an existing scenario. So we know one scenario okay that E should
31:21:51
come before Q right now over here again if we compare next two words the next
31:21:56
two words are Q A and QE okay so in QA and QE notice that the first letter is Q
31:22:04
so it is common which means we cannot identify much information from that but the second letter is A and E which means
31:22:11
we can determine that at any given scenario A will always come before E. So
31:22:16
we can notify that we can also create a scenario like that that A will always come before E and over here I'm denoting
31:22:24
this relation by uh an arrow which indicates that at any given moment E
31:22:29
should always come before Q because uh it is on the uh beginning end of the
31:22:34
arrow and uh the where it is pointing to uh should comes later and uh again we
31:22:41
will compare these two words Q E and RC. C. So if we compare these two words, we
31:22:48
can identify that okay Q should come before R. So we can also denote that
31:22:53
relationship that Q will become uh will be before R. Right? And over here now we
31:23:02
have these three relations. So based on these three relations we can actually establish something uh over here that we
31:23:09
can establish that A will always come before E and E will always come before Q
31:23:17
and Q will always come before R. So one of the sequence that we can return over here is that A E QR. Okay. So this is
31:23:26
one of the sequence that we have to maintain at any given cost because we are given these conditions based on the
31:23:34
words that were given. But thing is will this be our answer and actually this
31:23:39
will not be our answer. And the reason this will not be our answer is because over here we are given this particular
31:23:45
line that we need to return a string of unique letters from this words in the new new alien
31:23:54
language that is lexographically increasing order. The thing is over here if we look the original input the in the
31:24:01
original input we actually have one more unique character that we are missing and that particular unique character is so
31:24:08
we already took care of E we took care of A we took care of Q A Q E R all of
31:24:14
this we took care of but C the letter C we did not take care of it and the thing
31:24:20
is over here based on whatever the input that we are we were given originally we
31:24:25
cannot determine the position of C. But the thing is we know that C is also a unique character and the only thing we
31:24:32
know about the positioning is that for these four characters we can define some positioning like this. For C we cannot
31:24:39
determine any positioning but the thing is it has to be part of the answer as well and that is why we are told that
31:24:46
there could be multiple solutions and we need we need to return any of them. So in this scenario uh this could also be a
31:24:55
solution where a e QR and c we are placed at the end or this could also be
31:25:01
a a solution where a we we put c somewhere in the middle and eqr is uh
31:25:08
also placed like that. The important thing is that we need to maintain this order. As long as we are maintaining
31:25:13
this order because this C is one of those uh unique letters where we cannot
31:25:20
find the dependency for that. So we will need to take care of it as well and this is a very important detail that lot of
31:25:27
other videos have missed out and uh that is why it took me lot of time to make this video. I want to make sure that I
31:25:33
go through it completely. Now let's take one more example from the given input
31:25:39
and uh we will again try to find that what should be the answer for that.
31:25:46
So in the given input we are given the following words. These are the words that we are given in
31:25:53
the alien dictionary right and our aim is to find that what should be the answer in this case. Well, the first
31:25:59
thing is uh that we are what we are going to need uh in order to generate
31:26:05
the solution. In order to generate the solution, we are going to need two things. We are going to need
31:26:12
list of all the unique characters that exist. And second thing we are going to need is what are the dependency on uh
31:26:20
all between characters and based on these two things we will try to generate
31:26:25
some sort of order or some sort of pair and also remember that we will have to consider the scenarios where we could
31:26:32
find invalid strings as well. So I'll be explaining that uh in this uh in this example. So over here um if we see the
31:26:41
list of unique characters, the unique characters are W, R, T,
31:26:47
F, E. Okay, these are all the unique characters that we can find in this
31:26:53
particular input. Okay, now let's start making dependencies. Now in order to make dependencies at any given moment we
31:27:00
will have to compare two adjacent words and we are going to find first differing character and based on the differing
31:27:06
character we are going to establish some def dependency. So first of all the first uh first two words we are going to
31:27:12
compare are wr and wf. Okay in this case ww is common r
31:27:20
is common which means that first differing character is t and f and we already know that these words are
31:27:25
sorted. So because they are sorted we can determine that T should come before
31:27:30
F. Okay, we already know that this is good. Now what is what are the next two
31:27:36
words? Next two words and we are now we are done with this WRT. The next two words are WRF and ER. Okay, so WRF
31:27:45
and ER. Now in this case what is the first differing word? Well, the first differing word is first letter by itself
31:27:53
W and D. Which means we can make another dependency that W should always come
31:27:59
before E. Now we can ignore this. Again we compare next two words. So
31:28:07
E R and E T. So over here what is the first
31:28:13
diff? So E E is common. The first differing letter is R and T. Which means
31:28:19
that R should come before T. Next one is E TT
31:28:26
and R F TT. So over here the first differing character is E and R. So we
31:28:33
can also mention that E should always come before R. Okay. Now we have these
31:28:39
four dependencies for these four unique characters. Now let's try to see let's
31:28:44
try to create a dependency tree from this given input. So if we see we can
31:28:52
clearly see that okay W is dependent on E and E. So W comes before E then E
31:29:00
comes before R okay then for R comes before T and T comes before F. So this
31:29:10
becomes all the dependencies and if we notice all the unique characters they are already part of these dependencies.
31:29:17
So we are good. We don't need to do anything more over here. Now if we make that what should be the order of uh
31:29:24
letters. The order of letters in this case would be w TF and this would be the correct
31:29:31
solution. Now notice that in order to generate the correct solution what we had to do is we will we had to find all
31:29:38
the unique characters all the dependencies. Once we had all the dependencies we actually had to iterate over all the dependencies. see that
31:29:44
which dependencies are interconnected. Based on their interconnection, we have we actually had to generate this order.
31:29:51
And in order to do that, we are actually using uh graph theory. And how we are
31:29:58
using graph theory is basically all the unique characters in this case are actually nodes. And all of these
31:30:05
dependencies are actually edges between those nodes. And those edges can be
31:30:10
represented as in some form of adjacency list uh in some sort of hashmap. And then we will need to iterate over all
31:30:17
the entire graph. And then at any moment we will have to go through the graph and
31:30:23
find the solution that what what should be the order in which we are able to
31:30:28
iterate over all the unique characters which means that all the nodes inside the graph and we need to generate this
31:30:36
order of pairs. And if we are able to successfully generate this order of pair
31:30:42
we will return whatever we find. And if for somehow we find out that the input is invalid, we will have to take care of
31:30:49
that scenario as well. So first let's take a couple of examples where we we can find that the input could be
31:30:55
invalid. Now based on the English language we know that at any given moment if there are two words present W1
31:31:02
and W2 and we know that any single word so suppose W1 is actually prefix of this
31:31:08
W2. If that is the case then W1 should always come before in the dictionary
31:31:15
then W2. Let's take it by an example. Suppose we are given two words uh like bat and Batman.
31:31:23
If we are given two words like this. So if we compare if we start comparing these two words and see that what should
31:31:29
be their order we check that okay B is common A is common T is common right now
31:31:34
over here this actually ends there is actually an empty list there is nothing over here while over here there are
31:31:40
still some values so if that is the case we can determine that this W1 is
31:31:46
actually prefix of this W2 because these three characters are also present over
31:31:51
here and in that scenario this W1 should always come before W2. At any given
31:31:58
moment we identify that this particular character is not present in correct
31:32:05
manner. And suppose we are given an input like this that Batman and bat. If we at any moment encounter
31:32:13
this scenario, we can immediately return false because or we can immediately return an empty uh string because this
31:32:22
is a wrong ordering. So this is one of the failed scenarios where we cannot do anything right. So this is very
31:32:28
important to understand and we will have to take care of this in our solution. The second thing that that will not work
31:32:34
is that at any given moment suppose we are given list of words uh suppose the
31:32:40
words are like x a b x suppose we are
31:32:45
given list of words like this and what this means is that the first letter x
31:32:51
should always come before a. Okay. So based on these two we can establish this dependency. Based on these two we can
31:32:59
also establish that A should always come before B. Okay. And over here the next
31:33:06
thing is that B and X which means that what this is saying that B should always
31:33:13
come before X. So if you notice over here that we are actually stuck inside a
31:33:20
cycle that x will x needs to come before a a needs to come before b and b needs
31:33:26
to come before x. So at any moment in our graph whenever we are traversing
31:33:31
over all these unique characters and dependencies at any moment we encounter that okay there exist a loop and if we
31:33:40
detect that there is a loop from any particular uh node then we can return
31:33:45
false immediately or we can say that okay this is an invalid case where the string actually doesn't exist and we
31:33:52
will need to break out of the loop. Suppose we are given a custom example like this words and we are told that all
31:33:59
of these words they are lexographically sorted in the alien dictionary and now we need to return the order of words of
31:34:06
all the unique characters that we can find. So what should be the approach? Well, in order to do that we are going
31:34:11
to need two things. Now first thing we're going to need is all the list of all the unique words or all the unique
31:34:17
characters and we are also going to need uh the entire dependency uh between any
31:34:23
two letters that which should come first and which should come later. Right? So let's start working on it. Uh so first
31:34:29
of all we have B and A. Okay. So we will just add list of unique letters B and A.
31:34:36
And second word is B B Y which means that first differing character is A and Y. So we can establish a dependency like
31:34:43
this that uh a should come always before y. Okay. Now again moving forward with
31:34:50
next two values. So over here the first differing character is b and a which means that b should always come before a
31:34:57
and also u I forgot to add one more unique character y over here. Right
31:35:04
now uh this b should come before this a. So we will add that to our dependency
31:35:10
list as well. that B should come before A. Right? So this is one dependency and
31:35:15
over here we have the unique character D. So we will add the unique character D as well. Now we will we have this other
31:35:23
word uh these two words and in these two words a is common which means that D and
31:35:29
L are differing characters. So first of all we will add the word L over here and
31:35:34
over here we have this D right. Uh so we know that D at any given location will
31:35:40
come before L. Okay. So we'll just mention that. Now over here we have one more unique
31:35:47
character T. So I'll al also mention that. Now the next two words are these two words. Over here the A is common. L
31:35:54
and I are different. And also we have one more unique character I. Now uh we
31:35:59
know that there is a dependency between L to I. So we will also mention that that L should come before I. Now the
31:36:07
next two words are uh a i and a iir. Now
31:36:12
notice over here that this AI is actually prefix of this AIR right which means that this AI will always come
31:36:19
before this word air but we cannot determine anything regarding this R because this R by itself it has no other
31:36:27
thing to compare it its result with which means that though we have a unique word we don't know that what is the
31:36:33
intention for that particular word is and now let's see that in the dependency list that we have created uh amongst
31:36:40
these unique words. What are all the words that we are able to find a pair for? So one pair we were able to find is
31:36:48
for this one this B A Y uh let me just draw everything in same color. So B A Y
31:36:54
this is one pair which means we know that at any given moment this B A Y order has to be maintained like B always
31:37:01
has to come before A and uh Y and uh same goes for this D L I that D always
31:37:08
has to come before L and all L always has to come before I but in the list of unique characters we are given this R
31:37:15
and T as well that are not represented by any dependency which means we can show we can say that uh this R and this
31:37:23
T they are unique characters by themselves which does not have any sort of dependency right. So if we want to
31:37:30
see that what could be the potential different pairs we can make over here. Well there could be bunch of different
31:37:36
results like there can be so many different permutations and combinations. Let me just give you a few of them like most simple one would be B A Y D L I R
31:37:47
T. So this is one combination uh where notice that we are just
31:37:52
maintaining the entire order. Now second combination could be uh b d
31:38:00
a l y i r t. Now notice over here that
31:38:05
at any given moment we need to make sure that these two orders are are match up. So b is always coming before a and a is
31:38:13
always coming before y. So that is satisfied. Over here D is always coming before L and L is also coming before I.
31:38:20
So that is also satisfied. This RT they don't have any dependency. So it doesn't matter. We could have some pair like
31:38:25
this that B R T D A
31:38:32
Y L I. This is also a valid pair because notice that this B A and Y this is
31:38:39
maintained. This uh D L and I this is also maintained. this position of R and
31:38:45
T doesn't matter. So there can be bunch of different options that we can choose from and I'm just showing you that uh
31:38:51
these are the different results we can have right because we need to take care of unique characters as well. So don't
31:38:57
forget the unique characters they are really important. Now what should be the approach in this case? Well, one
31:39:04
approach is actually quite simple because we know that we have a unique
31:39:09
characters. We have the dependency. We can choose some data structure like hashmap. We can iterate over at any
31:39:15
point. Whenever we identify the dependency, we can iterate over the entire hashmap. We can from any point we
31:39:22
will try to see that whether it has any dependency or not. If it has dependency, we will go to that dependency. We will
31:39:28
try to iterate over those values and we will try to generate the order list. Right. So let's see that how it can
31:39:34
work. Suppose we create a hash set like uh suppose we create a hashmap like
31:39:40
this. Okay. Suppose this is our hashmap and based on these dependencies we know something that we know that okay for in
31:39:48
order for us to put down this B. We know that A has to come after B. Which means
31:39:54
A has dependency on B. Right? We will mention it over here. Now for this A, A has to come before Y. So a has to come
31:40:02
before y. Now for this y, we don't have any dependency. So we will just leave this value as blank. Now for this
31:40:09
particular d, d has to come before l, right? So we'll just mention l over here. Now this l has to come before i.
31:40:17
So we'll just mention I over here. For this i, we don't have any dependency. So we are good. And same goes for this t
31:40:23
and r that we don't have any dependency. So we are good. Now since we have this dependency tree let's see that what
31:40:29
would be the approach we can take over here. So in this scenario suppose if we want to calculate that what would be one
31:40:35
of those ordering pair what we can do is we will start traversing through all the
31:40:41
all of these values all of these unique characters and remember that this is hashmap. So in hashmap we are treating
31:40:49
these as key value pair key values and these are actually values. So in the
31:40:54
keys we are mentioning all the unique characters. In the value we are mentioning all the dependencies. Now
31:41:00
over here we will start iterating at this B. So first I'll just mark B as
31:41:05
that we are iterating over it. Right? Now from this B we identify that okay we need to have A before B. So again we go
31:41:13
to A because we will have to check all the dependencies. Right? We cannot just put any letter randomly any place right
31:41:19
because this B has some dependency. So we will have to go over that. Now this A has actually dependency on Y. So again
31:41:26
we'll go to Y and we'll just mark A as being as part of being visiting. And
31:41:32
over here we reach at this Y. Y don't have any dependency. So we are at this
31:41:37
Y. Now notice that we are actually traversing this graph in DFS manner.
31:41:42
Depth first search manner. Right? But and at in depth for search at this Y we identify that okay this Y does not have
31:41:49
any dependency. So we can just put Y to our order list. So we can just put Y to
31:41:54
our order list. Now from this Y we will do a back backtrack. We will again come back to A. Again we will do a backtrack
31:42:01
again. We will come back to B. And then we are we would be done with this B. Right? That okay we are done with this.
31:42:07
Now again we we start we ignore all of these. Now we start with this uh second
31:42:15
position. Now in the second position first we determine that whether we have calculated this value already or not. So
31:42:21
since a is already calculated over here so we ignore that so we can ignore the second case again we check that whether
31:42:28
this y we need to calculate it or not but y we have already calculated so we
31:42:33
can ignore this right so we will ignore this and now we'll move on towards this d now do you see any problem with this
31:42:41
one? Well, definitely we are seeing a problem with this one. And the problem is that over here the dependency is like
31:42:48
this that B has to come before A and A has to come before Y in order for us to
31:42:53
generate the dependency uh dependency order. But over here when we started
31:42:59
traversing the actual dependencies we are getting is actually in reverse order. You see that Y comes before uh A
31:43:07
and A is coming before B. So one way we can do it is that we can start
31:43:13
traversing like this one that over here we again come to this D for this D we find a dependency as L for this L we
31:43:21
depend find a dependency at I for I don't we don't find anything so we'll just put I over here then we backtrack
31:43:27
so again we put L over here and then again we backtrack and then we will put D over here and then we come to this T
31:43:34
like this I this L and this has already been done so So we ignore that. We come
31:43:39
to this T. T does not have any dependency. We put it there. I has already been processed and we reach it
31:43:45
at over the over here at R. Now this order list we got is actually correct
31:43:52
but in reverse order because the dependency should be like B A Y and uh
31:43:59
this should be DI but over here it's D L I in reverse order and same goes for B A
31:44:05
Y. So what we'll have to do is uh when we calculate the answer we will have to return the reverse of this answer and
31:44:12
that would actually satisfy uh these dependencies. So that is one way of
31:44:17
doing it right. Uh and there is also another way of doing it and the better
31:44:22
way is that when we are actually creating this hashmap we can actually do something different. Uh previously in
31:44:29
the hashmap what we are doing is that over here we had a key as all the unique
31:44:34
characters and as the value we had these dependencies exactly as they were
31:44:40
mentioned that for this particular B it is dependent on A for this particular A
31:44:46
it is dependent on Y. But the thing is that is not true. The actual true thing is that actually this Y the position of
31:44:53
Y should be dependent on A. that y cannot be present unless there exist an
31:44:58
a value before that. If we start so if we rather than storing the dependency on
31:45:05
value that is taking care of the value that comes after it if we start taking
31:45:10
care in reverse order. So let me show you what I mean by that. So suppose if we have a
31:45:16
hashmap like this and over here in the value we actually
31:45:23
present at any given value what should be the previous value that has to be
31:45:28
present in order for us to reach at that particular value. So what that would do is that if we want to calculate this B
31:45:35
we don't need to basically have any value right. So over here we will leave this as blank that for B we don't have
31:45:42
any dependency but for this particular A we actually have dependency on B that B
31:45:47
has to be there in order for us to process this A. So we will put a dependency over here saying that okay B
31:45:53
needs to be there for us to calculate this value A. Same goes for Y that A needs to be there in order for us to
31:45:59
calculate this value Y. Again we reach at this D and for the D we don't have any dependency so we'll just leave it
31:46:05
blank. But for this particular L again we will have to have a D over here. So we'll put a D over here. For so for this
31:46:12
T we don't have any dependency so we can leave it blank. For this particular I we actually have to put we have to have an
31:46:18
L before that. So we'll put a dependency over here. And for this R we don't have any dependency so we'll leave it blank.
31:46:23
Right. So this is the table we actually this is the hashmap that we work with.
31:46:31
And over here now let's try to iterate over this hashmap. Essentially our aim is to iterate over this entire hashmap.
31:46:38
Identify that at in any point if you are inside the DFS function you are not finding the repeated characters. So that
31:46:44
is item number one. Second thing to make sure is that you go through all the
31:46:49
characters and you start building up the order list. So over here we will get so
31:46:55
over here we will get uh we initially start at B and at B we don't have any child. So we are good to put B over
31:47:01
here. Now next uh and we can mark that B is already done. Now we are at this A.
31:47:07
So for A we need to check that whether B is done or not. B we check over here. B is already done. So we are good. Which
31:47:13
means that we can put A over here. So we will put A over here. Again we will mark A as being done. Again we are at this Y.
31:47:20
We check that okay A. Y has dependency on A. So we check okay A is already done. So we can put Y over here as well.
31:47:27
Now we are at this D. So D does not have any dependency. So we can just simply
31:47:32
put D over here and we can just mark this as done. Again from L we check for
31:47:38
D. D is already marked. So we put L over here. T does not have any dependence and we mark L. T does not have any
31:47:44
dependency. So we mark uh T has done. We can put it over here. Now this I has dependency on L. L we have already
31:47:50
marked that it is done which means we can complete this I as well. And for this particular R, it does not have any
31:47:57
dependency. So we can put it over here. Now if you if you notice this scenario, we are actually fulfilling both of these
31:48:03
dependencies and uh notice that this B comes before A and uh comes before Y. So
31:48:10
we are good with this dependency. This D comes before L and I. So we are also
31:48:16
good with the second dependency as well. And this T and R they were actually separate values. So it doesn't matter
31:48:21
wherever we put them as long as they are there uh it fulfills our purpose. And
31:48:26
this is the actual solution that we need to take care of that where initially we will iterate over all the words we will
31:48:33
create all the unique characters. Based on the unique characters we will create the dependency list. Uh based on the
31:48:39
dependency list we can actually create a hashmap uh that we are going to use to traverse as a graph. But thing is rather
31:48:47
than traversing the original hashmap we can actually create a reverse link reverse list of dependencies and we can
31:48:55
iterate over that just once using DFS or BFS anything but we are going to use DFS
31:49:01
because I want to master DFS for myself and we and that would be our solution.
31:49:07
So it took me lot of time to come up with this solution. It took me a lot of time to understand this problem. Okay,
31:49:12
let's calculate time and space complexity for this problem. So the time complexity for this one is is going to
31:49:17
be bigo of C where C is actually total number of characters that are given in
31:49:23
this original input words because notice that there are three actually three parts of this problem. The first part is
31:49:29
that we need to find all the unique characters like in order to in order for us to generate all the unique characters
31:49:34
we will have to iterate over uh all the characters that are given in the original input words. So that is one
31:49:40
part. Now second part is that we need to create a dependency and in order to generate the dependency again we will
31:49:47
have to traverse all the words and the third part is that we will have to uh so we are generating some sort of hashmap
31:49:54
and in the inside the hashmap we will have to iterate over all the values inside the the present hashmap. So at
31:50:00
any given moment the maximum work we are doing is iterating over the sum of all
31:50:06
the characters that are given inside this words. So that is why that would be the time complexity and if we want to
31:50:12
calculate the space complexity the space complexity would actually depend on the number of unique characters. So suppose
31:50:20
that in English language the number of unique characters maximum we can have is only 26 right and we are also told that
31:50:27
for this alien language the maximum number of unique characters we can have is also going to be 26. So space
31:50:34
complexity actually has a finite number and there is only so much it can grow.
31:50:40
So we can treat space complexity to be bigo of one or constant space complexity for this one even for us to creating
31:50:46
this additional hashmap. The second thing is that suppose if we want to calculate based on the number of
31:50:54
unique characters. Uh we there is also one equation where the space complexity
31:51:00
would actually be big of u plus whatever the u squar or n whatever the minimum
31:51:06
value of this is. And uh let me know in the comments if you want me to explain
31:51:11
the space complexity uh in a scenario where the number of unique characters are actually not finite and not 26. Like
31:51:18
in this case it's 26. So I will just uh leave it as it is. But let me know if you want me to explain that.
31:51:28
First of all, we are going to create our hashmap and we are going to actually create it outside of this uh alien order
31:51:35
method that is given because we want to use that hashmap to uh our to other to
31:51:42
our DFS method as well. So
31:51:49
and as a key we are going to use unique characters
31:51:56
and as a value we are going to use the dependency. So it would be list of characters
31:52:06
and we are going to name it reversed uh list because uh essentially we are just
31:52:12
reversing the adjacency list. Uh also we will create another hashmap
31:52:20
to uh essentially store the value of uh any parameter that we are already
31:52:26
currently visiting inside our DFS method. And uh
31:52:32
so we'll need to create an output of uh strings. So we can create a string builder variable.
31:52:42
Now the first uh thing we need to do is find all the unique letters inside our
31:52:48
uh given word string of words.
31:52:54
Now this is done. Now we will have to find all the edges and we will have to
31:52:59
add the reverse edges to our reversed uh reverse list hashmap.
31:53:10
Now at any given moment we need to check that whether the word two is actually prefix of word one or not. If that is
31:53:17
the case we can return false immediately and we have found a terminating case where the given uh string of words is
31:53:24
not valid. Okay, if that's not the case, we will
31:53:30
find the first differing character between two words and uh add it to our
31:53:35
add it to our hashmap.
31:53:42
And notice that we are actually adding the value to the second diff to the
31:53:49
second words differential character.
31:53:55
And the moment we find the first differing character, we can actually break out of that particular word. Now
31:54:00
we are going to iterate over the reverse list hashmap that we have created and we
31:54:05
are going to run our DFS function.
31:54:10
Okay, for all for all the keys present inside the reverse list hashmap, we are going to run the DFS function and we are
31:54:18
also going to check that at any given moment have we receiving the result as uh false. So we are just going to create
31:54:24
a boolean variable result and now we are going to call the DFS function and we
31:54:30
are going to uh provide the character inside the reverse list. And at any
31:54:36
moment if we identify that the result is uh for this result character is actually
31:54:43
false uh we will return uh empty list immediately.
31:54:52
Okay. Now uh all we need to do is that once we
31:54:58
once this DFS step runs u we should have our output inside the result. So we will
31:55:05
have to check that whether all the unique characters are be have been taken uh care of or not. So we are going to
31:55:12
check that whether the length of output
31:55:22
if that is less than the size of our uh list.
31:55:35
If that is the case, uh we can return false immediately because we haven't taken care of all the unique uh B unique
31:55:43
values present.
31:55:48
And if none of these cases uh happen, we will return whatever we find inside the
31:55:54
output. Now the only thing we need to do is we will have to create the DFS method.
31:56:04
Now first of all we are going to check that whether the current character C we are checking if we have already visited
31:56:11
that or not. If we have already visited that we are simply going to uh return
31:56:18
false. If that's not the case which means first we will add the current character to our
31:56:26
scene uh hashmap and we are going to mark the entry as
31:56:31
false. So that way whenever if we encounter the repeated value it will always return
31:56:39
false otherwise by default the value would be true.
31:56:45
Okay. Now for every single uh character
31:56:53
inside uh the current for the for the given character we will iterate
31:57:00
over inside the uh reverse adjacy list
31:57:07
and at any point if we encounter the result false we will return false immediately.
31:57:13
If that is not the case, uh we will remove the entry from the scene uh
31:57:19
hashmap. So
31:57:26
we'll set the entry as true and uh inside our output string we will append
31:57:31
the value
31:57:41
and for that particular character we are going to return true.
31:57:48
Okay. So I know this is a very long and too many lines of code. I'm going to put
31:57:54
this in the comments. Let's try to run the code.
31:58:03
Okay, seems like our solution is working. And uh also remember I was talking to you that we will have to take
31:58:10
care of all the unique characters. Uh here let me show you an example. So suppose we only have two characters H
31:58:18
and P. If we are only given input like this and we know that H comes before P right which means that uh in the result
31:58:25
we should be getting HP. So let's see that what okay so this is
31:58:30
this is accepted right but now let's say that we have uh additional character H A
31:58:36
and PB. Now over here we don't have any mechanism to measure this A and this B.
31:58:42
So they become unique characters right and now let's try to run the code for this particular test case. So if we do
31:58:49
that uh you are going to see that A and B would be at weird locations. So over
31:58:54
here see the important thing is in our output we are maintaining the order for this h and p and that is what it matters
31:59:01
like a and b over here in our output is actually behind this hp while over here
31:59:06
the a and b are actually at the beginning and then there comes hp. So it it doesn't matter as long as the order
31:59:12
that are that is given in the input is maintained. And now let's try to submit this code. And uh oh wow our solution is
31:59:21
actually 99% faster than all the other solutions. And uh I use lot of uh help
31:59:28
from the solutions tab from this uh lead core premium because it took me a lot of
31:59:34
time to understand this problem. So I'll be posting this in the comments. You can
31:59:39
check it out from there. And uh hope you like the video. It
31:59:53
so the lead code problem we are going to solve now is called swim in rising water. This one is a hard problem but a
31:59:59
very interesting and intriguing problem. So let's try to understand this. We are given an n cross n integer matrix called
32:00:06
grid where every single value inside the grid represents the elevation or height
32:00:13
at that particular mo point uh in this i and j location or any particular cell.
32:00:20
Now we are told that the rain starts to fall and at t times which means rain is
32:00:26
falling let's say from 1 minute then 1 minute it keeps on falling like 2
32:00:31
minutes 3 minutes 50 minutes up all the way up until t times then the depth of
32:00:36
water everywhere is t which means rain is proportional to the amount of time that has passed linearly now we can swim
32:00:44
from any particular square to all the four direction adjacent squares
32:00:50
If and only if the elevation of both the squares individually are at most t which
32:00:57
means we can swim from one square to any four directions as long as let's say
32:01:03
that uh the current t is let's say 15. So any particular square that has the
32:01:09
value 15 or less in all four all these four directions we can swim from this
32:01:15
current place. So the amount of t be becomes the critical point for us to
32:01:21
compare that are we able to traverse and in between any two squares or not. Now
32:01:26
we we need to make sure that we need to reach to the bottom right square where
32:01:32
we are starting from the top left square and we need to make sure that what is
32:01:37
the least amount of time we need to wait before we can reach to the bottom right uh right square. So let's try to
32:01:43
understand this with an example. The aim is we are given a grid like this. Now our objective is to traverse from this
32:01:50
particular node to this particular node. We are being told that at every single moment what is the elevation or what is
32:01:56
the height at that particular point. Now the thing is let's say that we are currently t is equal to zero point right
32:02:03
which means and we are currently located at this moment. So the thing is currently only zero units of rain has
32:02:10
fallen which means this particular portion is entirely filled up with rain water. So we are able to swim within
32:02:17
this cell. But the thing is this cell has a height of two. This cell has a height of seven and this cell has a
32:02:22
height of four. So we cannot traverse in any four directions right now. Let's say now enough time has passed and right now
32:02:29
currently t is equal to 3. Which means we can assume that let's say 3 m of rain has fallen. So if 3 m has rain rain has
32:02:37
fallen then this portion would have filled up completely because it only requires 2 mters to fill up. But thing
32:02:44
is all the other squares are still not filled up and because current t is equal
32:02:49
to three and we are currently initially located at this very first spot then we
32:02:54
can traverse to this particular spot any time after t is equal to 2. So at t is
32:02:59
equal to 3 we can still travel. when t becomes four then at t becomes four this
32:03:04
portion also gets filled up and we can also swim in this direction as well. So our aim was to reach from this
32:03:11
particular square to this particular square and we can only do that once the t amount of t gets four. So notice in
32:03:18
this case we are avoiding this path going down because this path is more expensive. So our answer in this case
32:03:24
would be t is equal to 4. Let's try to take one more slightly complicated example. Our aim is to reach from here
32:03:30
to here. Now we notice that there are bunch of different ways for us to we can go from here to here. We can take as
32:03:37
many paths as we want. And actually if we have to calculate mathematically how many paths it's going to take, I think
32:03:43
it's going to be n divided by number of ways we can move uh n factorial of that. So this is going to be a very expensive
32:03:50
operation if we have to manually brute force our way to check every single path. But lucky for us logical thing is
32:03:57
that we need to check only for some t positions. So let's say that initially
32:04:02
if we are at the position of t is equal to 5. So let's see that where up until what point can we reach if t is equal to
32:04:09
5. We know we can swim from here. No issues with this one. Then we cannot swim in uh into this cell because this
32:04:16
is a higher t but this is a lower t value. So we can go over here. Then nextly from this we can also go over
32:04:23
here because this is also lower than five. But we cannot go anywhere further. So we will have to increase the value of
32:04:29
our t to t is equal to 6. Still we cannot go anywhere further. If we do t is equal to 7 then we can traverse up
32:04:35
until this point. And notice that at t = 7 we can also traverse to this point
32:04:40
because this is lesser than the current t value we have. So the minimum amount of t we need to complete all the values
32:04:46
is not going to be t is equal to 6. Even though this value is six, it is going to be t is equal to 7. So one more way to
32:04:53
explain this is to find a path that traverse from this one to the last like
32:05:01
top left to bottom right corner and in that path find the minimum like the
32:05:06
maximum value of t that is required. So that would be our answer. So now let's try to reverse engineer our way through
32:05:14
this one. We already know that let's say if we are being told that you have this
32:05:19
particular example and for this example you need to make sure that you need to iterate over all the values only and
32:05:26
only if for any particular given t. So let's say that we ask you that if the t
32:05:32
is equal to three are you able to reach to all of these values. So logically what we will do is we will start from
32:05:38
here and then we will see that what are all the cells that has less value than t. So this cell has less value than T.
32:05:45
Then next this value has less less value than T. And then we can say that now we cannot go anywhere further. We can also
32:05:51
try to do a backtrack and check for the other possibility. But still we won't be able to do it. So logically we need to
32:05:57
do like depth per search or breath per search in order to find the path we need
32:06:03
to take to reach to the end. That is number one fact. The other thing is after finding the DFS or BFS we don't
32:06:10
know that what should be the optimal value of T in order for us to reach to the very end. So for that there are
32:06:18
bunch of different possibility but one common way that is for sure is that the minimum value of t can be uh zero. So
32:06:26
whatever the smallest value is so let's say the smallest value is zero. So the let's see the possible values of t can
32:06:32
be zero or t k t has to be less than the maximum value we currently have. So in
32:06:38
this case the maximum value we have is 24. So t has to be somewhere between 0
32:06:43
and 24. That is a given fact like less than or equal to. Why? Because all the
32:06:49
time if t is equal to 24 then we have access to traverse to every single cell
32:06:54
in this g given entire architecture. So if we can traverse to all the cells for sure we can find a path that can uh lead
32:07:02
us from top left to the bottom right corner but so now we found one condition
32:07:07
on where the T should be able to move. This is number one thing that what are what could be the potential value of the
32:07:14
T. Second thing is we already know how to calculate that for any particular given value of T are we able to traverse
32:07:21
to all the cells and reach to the bottom right corner or not? We can do this in both the ways. We can use a breath first
32:07:27
search or we can use a depth first search in order to do this one and it's a pretty common and standard method that
32:07:33
logically we are going to be traversing over all the different paths wherever this condition meets up and the moment
32:07:39
we find out that the condition is currently satisfactory we can actually move to all four directions to find the
32:07:46
value we are looking for. So what I'm suggesting is instead of checking for all the potential values of t which is
32:07:54
going to be pretty expensive operation why don't we use binary search in order to find the uh the correct value of t
32:08:01
that makes sense. So what I'm suggesting is let's say that for this particular given given value we know that the t has
32:08:09
to be somewhere between 0 and 24. So what we can do is we can treat this zero as the left pointer this 24 as the right
32:08:16
pointer. Then we will try to find the midpointer. Midpointer is going to be 12. So let's see that if we use the t is
32:08:22
equal to 12, are we able to reach to this bottom right corner? So we can go
32:08:28
down this path. That's for sure. But now after this five, we cannot go anywhere because this is 16 and this is 21. So 12
32:08:35
does not work. Which means the answer of t has to lie somewhere between 12 and
32:08:40
24. So we update so sorry not 12 like 13 and 24. So we update our left pointer
32:08:45
and right pointer once again we try to find the midpointer. So in this case the midpointer is going to be uh I think
32:08:52
somewhere between 18. So let's see at 18 are we able to figure out? So yes we can
32:08:58
go down this path. Yeah for sure at 18 we can take this path and once again we
32:09:04
should be able to complete our answer in this manner. No issues with this one. So yes 18 works. So once again now we have
32:09:11
our left pointer as 13 and right pointer as 18. Once again we will do the binary
32:09:16
search. So we will find uh the middle pointer to be 15. Let's see at 15. Are
32:09:21
we able to find the correct value we are looking for? No. Right? Because the 16 we would not be able to cross this
32:09:27
threshold. So next possible value is going to be uh 15 and once again 18
32:09:32
sorry 16 and 18. So the logical step would be 17 17 would work because we
32:09:38
would be able to find out. Then once again uh from between 16 and 17 we also
32:09:43
have to find that are we able to do it. So if we do the midpointer once again the value would be 16 and for 16 we
32:09:49
should be able to find the answer. So logically we had to do like instead of
32:09:54
doing 0 to 24 steps we only did five steps to find that value 16 and that we
32:10:01
did it using binary search. So logically in this problem what I'm suggesting is that we use breath first search or depth
32:10:08
first search whichever one you would like to choose uh in order to iterate over all the cells and we do this with
32:10:16
doing the binary search on the value different values of t and the value the
32:10:22
range for t is going to be the smallest element like zero less than or equal to t less than or equal to whatever the
32:10:28
maximum element we have inside our grid and uh somewhere between that we would try to find the value of t. So this
32:10:34
solution would work perfectly fine. If we have to calculate time and space complexity in this case the bfs or dfs
32:10:40
would take of n square work because we have n cross n grids and for one iteration and we will have to do this
32:10:47
log and time because we are trying to find different values of t. So it's going to be n² log n uh in terms of time
32:10:54
complexity in terms of space complexity depends on how you implement your breath first search or depth first search. If
32:10:59
you are using recursion and you if you are using like a stack uh recursive stack to store those values then it
32:11:05
might take big go of n square space as well. So just be mindful of that. Now
32:11:10
let's quickly see the coding solution for this one. So the very first thing we are going to
32:11:15
do is uh we are going to mark the value of n. Then we are going to initialize
32:11:21
our left pointer and right pointer. This is going to be the cell locations. And then we are checking that while the our
32:11:27
left pointer is less than right pointer we are going to find the midpointer that we will have to iterate over. And on top
32:11:35
of it we are also going to check or we are going to call our helper method call swim uh can swim and which checks that
32:11:42
for any particular given grid depending on the midpointer are we able to reach if we can then we shift our right
32:11:50
pointer to the midpointer. If we cannot then we update our left pointer to go right + one. So this is our binary
32:11:55
search method. Now let's understand our can swim method. So in the can swim we
32:12:01
have the given grid as the input and the different values of t we are working with. On top of it we are checking that
32:12:07
first of all what is the length of the given grid. We are also having a visited boolean hash set that defines that these
32:12:14
are the cells we have visited so far because we don't want to be stuck inside the infinite loop in breath for search
32:12:19
or depth for search. And we are going to call our DFS method in this case where we are passing in the grid the nodes
32:12:25
that we have currently visited the i and j location and we are also passing in
32:12:32
the different values of t. Now this is going to be our recursive d uh dfs method where first thing we are checking
32:12:38
is that what is the given length of n. Then we are checking for the scenarios that if we are going out of bounds. So
32:12:46
the these four conditions are for going out of bounds or we have already visited that node or we notice that the well
32:12:53
location of the grid position is greater than the current t value then we can
32:12:58
return false that we cannot go to that particular cell. If that is not the case and we check that the current i and j
32:13:06
position is at the bottom right then we can simply return true saying that yes we are able to reach to bottom right
32:13:12
corner. If that is not the case then we mark the current node as visited and then we try we call the DFS method in
32:13:19
all four directions and once again recursively repeat the same process. So this is the coding solution. So
32:13:25
basically after this recursive process ends we should either receive true or false for any particular t value and
32:13:32
inside our main method we are trying out bunch of different t values uh and making these uh various calls. So this
32:13:39
is the whole solution. Now let's try to run the code.
32:13:45
Okay, seems like our solution is working as expected. Let's submit this code
32:13:51
and our code beats almost 98% of all the other solutions which is like one of the
32:13:57
fastest solutions uh for this particular hard problem. So I hope you find it useful. Once again the solution is
32:14:03
present on our GitHub repository. So feel free to go ahead and check it out from there. Thank you.
32:14:19
Dynamic programming is the toughest and most important part of any DSA interview
32:14:24
question and I have decided to make a full course on that. By the end of this course, I can guarantee you that you
32:14:30
will become master in all dynamic programming questions. And in this course, we are going to discuss what is
32:14:37
dynamic programming, brief history, what are the different ways to use dynamic programming, recursion, tabulation,
32:14:43
memoization, all the characteristics, when to use dynamic programming, what are the most effective ways. Trust me, these
32:14:50
questions have been asked by hundreds of companies thousands of times. So without any delay, let's get started.
32:14:58
The term dynamic programming is a repetition of being a scary term but it's not that complicated. Actually this
32:15:05
dynamic programming approach is nothing but a problem-solving technique and this
32:15:11
technique involves you of taking a bigger problem and then start breaking into bunch of different smaller sub
32:15:18
problems. Now for each of the sub problems that you are already calculating the results you are also
32:15:24
going to store this result and this is going to be the important procedure in this whole dynamic programming scenario
32:15:30
that because you are storing the results whenever you need to recalculate or
32:15:36
refind the same value. You can simply quickly look up in the stored values and then you would be able to find answer
32:15:42
for that and eventually you would be able to find the correct solution for the item that you are looking for. using
32:15:49
dynamic programming. Now in order to achieve that we are going to use bunch of things like recursion or memoization
32:15:56
or tabulation. But let's try to understand dynamic programming with a very simple example of a Fibonacci
32:16:03
series. This is the simple equation of for any Fibonacci series and we are given the
32:16:11
first two values of the Fibonacci sequence where Fibonacci of zero is going to be zero and Fibonacci of one is
32:16:18
going to be one. Based on these two values and this function we can calculate any particular Fibonacci
32:16:24
number. We can calculate number for even Fibonacci of 100 and that is going to be sum of Fibonacci of 99 plus Fibonacci of
32:16:31
98. Now let's try to understand that if we have to calculate or find the value
32:16:38
for Fibonacci of five how we are going to be able to do it without using dynamic programming and for simplicity
32:16:44
we are going to be using recursion to solve this problem. Logically Fibonacci of five we know is going to be sum of
32:16:51
Fibonacci of four plus Fibonacci of three. Now same way subsequently.
32:17:00
Now notice that in order to calculate Fibonacci of four we will have to do all
32:17:06
of these calculations. And same way in order to calculate Fibonacci of three we will have to keep do bunch of different
32:17:12
more calculations. But notice over here we are calculating the value for Fibonacci of three. Over here we are
32:17:17
calculating the value of Fibonacci of three. Over here we are calculating the value of Fibonacci of two. once again
32:17:23
Fibonacci of two and once again Fibonacci of two. So we are doing lot of
32:17:28
repeated work and for problems like these dynamic programming would be the
32:17:34
correct and most efficient approach because now notice the scenario that what if we just simply create an array
32:17:41
where we are going to store the result of every single Fibonacci value starting from value zero all the way up to five
32:17:48
and uh all we need to do is store those results and whenever we need to
32:17:54
calculate the new value We can always look up in the previously stored results. So let's try to understand this
32:18:01
with an example. We know the base case Fibonacci of 0 and Fibonacci of one is going to be value 0 and one. For value
32:18:07
Fibonacci of two, the value is going to be sum of previous two elements. So this is going to be one. Same way Fibonacci
32:18:14
of three is going to be sum of previous two elements. So so on and so forth. We can keep on repeating for every single
32:18:21
value and we would be able to generate Fibonacci of all the way up to million values in very quick fashion. Now notice
32:18:29
the difference between two approaches. Without dynamic programming, we are doing bunch of repeated work for our
32:18:35
recursion call. And the time complexity in this case is actually going to be we go of 2 to the power n which is very
32:18:41
expensive like trust me this is very expensive and most of the computers cannot even compute more than 100 numbers. For this approach dynamic
32:18:49
programming approach time complexity is actually going to be bigger of n simply. So you can compute billion values and
32:18:56
still computer would be able to run very efficiently. And this is the true power of dynamic programming.
32:19:04
Dynamic programming was originally invented in actually 1950s as part of
32:19:09
the way to calculate some complex problems where we are already storing the results and we would be able to
32:19:16
recalculate that in bunch of other places. Now computers were not popular in 1950s but the underlying concept
32:19:23
allowed computers to quickly look up the previously computed values and come up
32:19:29
with the answers. This was actually developed by a very popular mathematician called Robert Bellman. And
32:19:36
yes this Robert Bellman is the same Robert Bellman from our very popular Bellman and Ford algorithm. And if you
32:19:45
know Bellman and Ford is a great algorithm if you want to find the shortest path amongst any graph where
32:19:52
you have negative values as well. So which is like a much better approach compared to dysters which only works
32:19:58
with non- negative values. So now coming back to our problem of understanding what dynamic programming is.
32:20:07
Now we know that we'll have to deal with three distinct terms while speaking about dynamic programming. First one is
32:20:14
a recursion. Well, it is nothing but a simple way for you to take a bigger
32:20:21
input. Start breaking this bigger input into smaller input and smaller input and
32:20:26
again smaller input until you reach to a case where it is very easy to calculate.
32:20:31
And once you have this result, you would be able to build the su the next result. Then you would be able to build next
32:20:37
result and so on and so forth. You would be able to solve this problem completely. And this is the simple recursive approach. Next category is
32:20:45
memorization. So memorization is actually very closely related with
32:20:50
recursion where for recursive call whenever you are making and whenever you are doing any sort of computation
32:20:57
whenever you find some result you start to store that result in some fashion and
32:21:03
you are actually memorizing these values. So say in future if you have to
32:21:08
make another recursive call for any particular item and then you need to make that calculation you already have
32:21:15
those values stored in the result and this is called memorization. So
32:21:21
recursion and memorization would always go hand in hand in any dynamic programming approach and combination of
32:21:28
these two is actually going to be called top-down approach. Now why it is called
32:21:33
top down? Remember how recursion works. For recursion you are going to start
32:21:38
with the topmost or most largest or extreme value and then you are going to
32:21:44
be taking on smaller and smaller subpros and once you reach at a base case then
32:21:50
based on that you would be able to start making calculations. So there would be a recursive call stack that you are going
32:21:57
to take care of and which will store all the results. Now the third term uh
32:22:03
associated with dynamic programming is going to be called tabulation. So tabulation is slightly different
32:22:10
compared to our recurs recursion plus memorization approach. Now in even in
32:22:15
tabulation we are storing the result of items that we are calculating. But the
32:22:20
different part is that let's say that we are currently given a problem size of this and where we need to store the
32:22:27
value for something associated with term 50 or value 50 as part of dynamic
32:22:34
programming tabulation. We are actually going to start calculating results starting from value zero all the way up
32:22:40
to value 50. And this is going to give us the result all the way up to all of
32:22:46
these values which we would have stored. So notice that instead of starting at
32:22:51
the biggest value, we are actually starting at the smallest value and then we are building our solution with bigger
32:22:57
and bigger values and eventually we would calculate the results for all 50 values. So logically this is also a
32:23:05
dynamic programming technique that is going to be opposite of the top down approach and that is called bottom upro
32:23:12
bottom up approach where you are starting at the bottom and then you reach at the very top and both of these
32:23:18
ways can be used in different scenarios.
32:23:24
Many times you can also use them interchangeably uh depending on the problem statement. But there are some
32:23:29
scenarios where it makes sense to use either top-down approach or bottom up
32:23:35
approach. So let's understand those scenarios as well. Uh logically let's say that if you are already given that
32:23:43
the problem can be easily solved recursively, it makes sense to use a top-down approach because the recursion
32:23:49
goes hand inhand with memorization and dynamic programming. it is going to be uh less coding approach and you can also
32:23:57
simplify your implementation and understanding of it. Uh next thing is you will also have to keep track of the
32:24:04
recursive call stack. So that is something that you need to be aware of
32:24:09
and also understand that how the time complexity is going to affect. The other thing with recursive approach or top-
32:24:15
down approach is that many times you don't have to do all the calculations. So if you only need to do selective
32:24:23
calculations in order to calc to generate the result uh then it would make sense to use top- down approach and
32:24:31
uh there can be many examples of this but one common example is a problem called unique paths which you are going
32:24:37
to solve in this uh subsequent lead core problems that we will do. Uh same way
32:24:43
let's understand some of the benefits of bottom up approach. If the problem can be easily completed in a bunch of
32:24:50
different sub problems then it it becomes a good candidate. If you have a
32:24:55
good base case and based on the base case you can build on top of that base
32:25:00
case for all the other subsequent value then it makes sense to use bottom up approach. If you need to do all the
32:25:07
calculations for all the sub problems and store all of those results which means you are not doing selective
32:25:12
calculations and you are not doing sparse calculation but you are doing dense calculations then it makes sense
32:25:18
to use bottom of approach and remember that this is going to be an iterative approach so you don't have to worry
32:25:25
about keeping track of any different type of call stack so it works perfectly
32:25:30
fine and these are the two common differences now I We are at the very
32:25:35
beginning of our dynamic programming journey. So it's tough to understand all of these statements. But I can guarantee
32:25:41
you that after completing our 20 lead code problems, you would be able to very easily identify the difference between
32:25:48
bottom up approach and top- down approach and when to use which one and how to use memorization, recursion and
32:25:55
tabulation. So I guess I gave you like good introduction of what dynamic programming
32:26:01
is, what to expect. basically take a bigger problem and make make bunch of
32:26:06
different smaller problems or do like a recursive approach and try to come up with like a smaller and smaller sub
32:26:13
problem and eventually store those results and after storing these results
32:26:19
come up with the solution. So that would reduce your time complexity significantly. So understanding what
32:26:25
dynamic programming is will allow you to understand more complex dynamic programming topics such as
32:26:31
two-dimensional dynamic programming. So we will understand the concept of that as well and then we will dive deeper
32:26:37
into dynamic programming questions.
32:26:43
So 2D dynamic programming is actually nothing but an extension of the original dynamic programming that we all know.
32:26:50
Now in typical dynamic programming we are basically given a set of problem
32:26:56
that we are trying to solve and in order to solve that problem we store the information of all the substep of that
32:27:03
problem in an array or a string like format. So basically if we have to take
32:27:09
the classic example of the uh climbing stairs problem basically we are being told that we need we are given a bunch
32:27:16
of uh stairs and at any given position we can climb one step or we can climb
32:27:22
two steps and we need to find that how many distinct ways we can reach at the top. This is a classic dynamic
32:27:29
programming example and as part of the solution what we do is we take that if there is only one step how many distinct
32:27:36
ways we can climb at the top. Same way if there are two steps, how many distinct ways we can climb at the top
32:27:41
and so on and so forth and we would keep on pertaining that information in an array-like format and store it and then
32:27:48
based on that we would be able to very easily calculate the final result only by looking at the previous two values
32:27:54
rather than going and redoing the whole exercise. That is the core concept and power of dynamic programming. In
32:28:02
two-dimensional dynamic programming basically we take that up a notch. We
32:28:07
typically break the problem down into a pieces of set of permutations and
32:28:12
combinations. And let's say that we are given a problem where we are given a
32:28:18
particular word and we are given another word. So let's say that is like a substring of the original word one and
32:28:25
we need to find out that how many distinct substrings that we can make out of this second word two that we are
32:28:31
given based on this first word. Now in that case the problem becomes exponentially difficult if we just have
32:28:38
to use single dynamic programming. We won't be able to solve it. So what we are going to take it that let's say that
32:28:44
for word one we are given the values ab a b uh a c something like this and word
32:28:50
two we are given as the value of a b and c. So in this case what we can do is we
32:28:56
can take every single possible combination of word one against word two
32:29:02
in a gridlike format. So where we are going to have a scenario that what if uh
32:29:08
we are we have word two present over here and what if we have word one present over here and for all of the
32:29:15
permutations and combinations we would treat that if let's say for some reason if word one only had values a b and word
32:29:23
two only had the value a how what would be the total number of substrings that we can generate and that would be
32:29:29
calculated based on a cell value that represents over here where we can notice
32:29:34
that we are currently taking care of a and b from this word two and from word
32:29:40
one we are taking that as if it only has value a so so on and so forth you can understand all sorts of different
32:29:46
questions and examples where we can use 2D dimen uh uh dynamic programming but
32:29:52
the core underlying concept is that now instead of just taking care of a single
32:29:57
parameter we are actually worried about two distinct properties and based on
32:30:03
that we are actually going to create a grid-like format and for this grid we
32:30:08
are going to iterate over every single combination to solve the problem. Now let's visually represent for a typical
32:30:15
dynamic programming we saw the classic example of climbing stairs where we had the values being stored with within an
32:30:22
array and for any particular value x the answer of x was directly
32:30:28
reliant on the previous two values that we have already calculated and that was the sum of the previous two values. So
32:30:34
let's say that this value was a and this value of b. We could have said that the x is equal to a + b. This is not going
32:30:41
to be as straightforward in a 2D dynamic programming because now we are dealing with a grid-like structure and we
32:30:47
already have calculated values beforehand. So let's say that there is any particular cell X that we
32:30:54
are trying to work upon. It could be possible that we only care about the
32:30:59
direct diagonal value. It could be possible that we care about the top value and the side value or it could be
32:31:04
possible that we care about all of these three values and some form of uh
32:31:10
addition multiplication subra subtraction whatever that case might be would be the recurrence relation in this
32:31:17
case to solve this problem. So it is really important in this in the 2D
32:31:22
dynamic programming to first of all understand that number one what is going to be the base case and what is going to
32:31:29
be the recurrence relation and based on these two information we need to start
32:31:35
populating our matrix to solve the problem that we are currently given at hand.
32:31:41
So number one program number one type of problem that frequently occur is any
32:31:46
particular grid based problem. So whenever you see that you are trying to deal with two distinct type of character
32:31:54
and it makes sense for you to generate a grid to iterate over all the permutations and combinations definitely
32:31:59
this is a clear clue that you can use 2D dynamic programming in order for you to
32:32:06
solve this problem. Second one is typically substring related problems. So whenever you are given like two words or
32:32:13
you you are trying to find all the substrings of one word from the other word or you are given two words and you
32:32:19
are trying to see that how many distinct ways you can generate like word two from word one all of these things can also be
32:32:27
done using 2D dynamic programming and third one are typically partitioning and
32:32:32
permutation and combination problems. So for partitioning problems uh it could be
32:32:38
possible that we are only given just one set of value but we will have to partition it in such a way that multiple
32:32:45
different form of path are being generated from that particular given value and for each of the subsequent
32:32:51
path we might have another classic path on their own and that in such scenarios
32:32:57
we can also start thinking about using 2D dynamic programming and don't worry we are going to see examples of of all
32:33:03
these three. Now, what are the typical prerequisites
32:33:09
in order to understand this dynamic programming course? Now, usually I don't put prerequisites in my courses that I
32:33:16
am that I teach. But thing is this is a special one and this is an advanced level course. So, I would highly
32:33:22
recommend that first you understand or you have good grasp over the concept of
32:33:27
string and array because this is really important. Now second thing I want you
32:33:33
to learn is to have idea on what typical normal dynamic programming works because
32:33:38
this is going to taking up one step further than we already have. And third
32:33:43
thing that you should be familiarized with or have understanding about is that how typically memoization and tabulation
32:33:51
works. So these two are typical different ways of iterating over any particular problem. uh and you need to
32:33:59
encounter like recursion and uh iteration in different scenarios. So you
32:34:04
need to understand like bottom up and top down approach and different dynamic programming concepts. So I would highly
32:34:10
encourage to have information about these three things. Now I have already created videos and courses on each one
32:34:17
of them. So you should be able to find it very easily. Okay. Now without any delay, let's get uh started with the
32:34:24
most important part of this course.
32:34:30
The lead code problem we are going to solve now is called climbing stairs. We can see that this one is an easy problem
32:34:35
and also a very well-like problem. The statement is quite straightforward that we are trying to climb a staircase that
32:34:41
currently has n steps to reach at the top. Now each time we have the option to
32:34:46
either climb one step at a time or two steps at a at a time. Now we need to
32:34:51
determine that in how many distinct to unique ways we can reach to the top of
32:34:57
the staircase. So let's try to understand this with an example. Suppose we are only dealing with just one single
32:35:02
step. How many distinct ways we can reach to the top? Well, obviously there is just one way we can re reach to the
32:35:08
top by taking one step. So in this case we need to return one as the answer. Let's say for the same example instead
32:35:14
of one, what if we have two steps and now we are trying to reach to the top. What are the distinct ways? So first is
32:35:19
distinct way is take one step and then again one step and second distinct way is to take two steps directly. So in
32:35:26
this case we need to return two as the answer that these we have two distinct ways to reach to the top. Same way if we
32:35:32
have three distinct uh three steps uh how many distinct ways we can reach to the top? Well we can continue by taking
32:35:39
just one step at a time. So that is going to be our path number one. Second path we take two steps and then we take
32:35:44
one step or third path we take one step and then we take two steps. So overall
32:35:50
now we have three distinct ways to reach to the top. So this is what we need to return as part of the answer. Now let's
32:35:56
try to understand the most common brute force approach to solve this problem. Well uh the idea is quite
32:36:02
straightforward. Let's say that we are currently dealing with five different stairs. Now at any given moment uh
32:36:08
starting from position zero we have two options. First option is either we take one step or uh the option is we take two
32:36:15
steps. So let's make a decision tree based on that. Currently we are at step zero. What are the options we have? We
32:36:20
can take one step and reach to step number one or we can take two steps and reach to step number two. Same way at
32:36:26
one we can take one step and reach to step number two or we can reach to two uh uh step number three. Same way we can
32:36:32
reach to step number three or we can reach to uh step number four. And over here we can reach to step number four.
32:36:38
And we can reach to step number five. Now the moment we reach step number five, this is one of the unique paths.
32:36:45
So we will note this path down and keep on iterating with our uh possible
32:36:50
choices. So once again over here we will have two choices four and five. And once again we will have here one more choice.
32:36:56
But now notice that there is a big issue with this one. Why? Because at every single position we have two dist
32:37:03
different ways to choose from. And whatever path we take depending on that we are once again going to be dealing
32:37:09
with two more positions. So in this case the uh time complexity is actually going
32:37:14
to be 2 to the^ of n which is a very expensive time complexity and we will have to find ways to do things smartly.
32:37:21
So that's where the most beautiful concept of the entire computer science come into the place and that is called
32:37:27
dynamic programming. Now notice over here that we are doing bunch of repeated
32:37:33
work for the same amount of thing that we are calculating. We are calculating that what are all going to be all the
32:37:38
different options from two and same calculation we are doing it over here. We are calculating that what are going
32:37:43
to be all the different options from three and same thing we are calculating over here. So why don't we just memoize
32:37:50
or store the information that we have already calculated uh and use it
32:37:55
whenever we needs to use it uh sometime in the future and that is the whole idea of dynamic programming. So in order to
32:38:03
do that or in order to achieve dynamic programming we will have to understand two things. what is going to be the base
32:38:09
case scenario or the minimum starting point for us to understand or start building the solution and second one is
32:38:15
what is going to be the dynamic programming correlation amongst different parties. So first let's
32:38:21
understand the base case. Well base case is quite straightforward. Let's say that if we are given zero steps how many
32:38:27
different ways we can reach to the zero steps. So we can only have one distinct
32:38:33
way to reach to the zero step because where we are not taking any steps. Let's
32:38:38
say if we are only given one step how many different ways we can reach to the top. We only have one way to reach to
32:38:44
the top that is by taking one step. So these two are going to be our base case scenario where uh DP of zero is going to
32:38:53
be defined as one and DP of 1 is also going to be defined as one. So now these
32:38:58
are the most common entries that are always going to be true and that we can calculate very easily. Now let's
32:39:03
understand that what is going to be the dynamic programming recurrence relationship between uh any given two
32:39:11
parties. So for that let's try to understand the scenario. We are currently dealing with these five steps
32:39:17
and we are trying to determine how many unique ways we can reach to step number five. So the most simplest logic you can
32:39:24
think of is that whenever you need to reach to step number five, what are the
32:39:29
ways to reach to step number five? Well, one way is that either we reach to step number four and then take one step or
32:39:37
second way is that we either somehow reach to step number three and then take two steps. Now you must be thinking that
32:39:44
there is one more way where we can take one step from step number three and then take one more step to step number four.
32:39:49
Well, we already covered this case when we first mentioned that whenever like all the different ways you can reach to
32:39:55
step number four and then take one step. So overall, we only have two unique ways
32:40:00
to reach to step number five and that is through step number three and step number four. And once we are at either
32:40:06
one of these locations, we are guaranteed to reach to step number five. So all the ways we can reach to step
32:40:12
number three are all the unique ways we can reach to step number five. Same way all the ways we can reach to step number
32:40:19
four are all the ways we can reach to a step number five and this is going to be sum of these two unique ways. So this is
32:40:26
going to be our recurrence relation. Why? Because we are we have the liberty to choose from one or two steps and uh
32:40:32
if we do it like reversely we can just calculate that okay uh we need to
32:40:37
calculate all the ways to reach to step number three or step number four and do the sum and that is going to be our recurrence relation. Based on that we
32:40:44
can actually create a mathematical formula that at any given moment DP of I is going to be DP of I minus1 plus DP of
32:40:54
I minus 2. And based on this equation now we can solve all our problem very
32:41:00
easily. Let's say that now we are trying to solve for the answer n= 6. We already
32:41:06
know that this is the formula we are going to use to solve this problem. on top of it, we already have the first two
32:41:12
values being filled out. Why? Because DP of 0 1 2 3 4 5 and then this is going to
32:41:18
be the value number uh six. Now for DP of zero, we already know it's one and DP of 1, we already know it's one. So say
32:41:25
based on this equation, DP of 2 is going to be 1 + 1. So now we can notice that
32:41:31
if we have to reach to uh step number two, there are two unique ways to reach to step number two. And same way has
32:41:38
been proven by this equation as well. Same way for step number three the sum is going to be 1 + 2. So we can do it
32:41:44
three. Same way step number four we can do sum of these two values. So it is going to be five. For step number five
32:41:50
the sum is going to be 5 + 3. So it is going to be 8. And for step number six it's going to be 8 + 5. So answer is
32:41:56
going to be 13. So there are going to be 13 unique ways to reach to step number six. And the solution becomes quite easy
32:42:03
and simple. And notice what we just did is we first establish a base case then
32:42:08
we established that what is going to be the relationship and then based on that we kept on populating further and
32:42:14
further values. So even now if you have to calculate for n is equal to 100 you can do it very easily and very quickly.
32:42:20
So logic is quite straightforward. Uh now we can do one more improvement over
32:42:25
here because we are only dealing with two previous values. Instead of using an entire array to store all the values, we
32:42:32
can just have two variables previous one and previous two. And for every single value, we can uh just resolve these
32:42:39
values and keep on updating for a subsequent current values. So we'll see this in code that how this can work. But
32:42:46
basically this is the whole idea and based on this you can solve this problem very easily and very quickly. If you see
32:42:52
time complexity, it is going to be big of n. And for space complexity, well, if you use a full array, it would be big of
32:42:58
n. But if you just use couple of variables like this, it is going to be big of one. So now let's try to see the
32:43:04
coding solution for this one. Now the coding solution is quite straightforward. First, we are going to take care of the base cases that if
32:43:10
given n is equal to 0 or 1, we can simply return one. If that is not the case, we are going to initialize two
32:43:16
variables to keep track of the previous two steps values. And the initial values are going to be 1 and 1 for step zero
32:43:23
and step one. Then we are going to iterate over the given loop starting from i is equal to 2 or from the third
32:43:30
step all the way up to the n. And for any particular current step the number
32:43:36
of ways we can climb up to that step is going to be sum of previous two elements. So we will add that and then
32:43:43
we will simply swap the values between previous two and previous one. So previous one is going to become the
32:43:49
current value and previous two is going to become the previous one value that we had before and after keep we keep on
32:43:56
updating that in the end we can simply return previous one as the answer and
32:44:01
that would be the number total number of ways to reach any particular nth step. So let's try to run this code.
32:44:10
Okay, seems like our solution is working as expected. Let's submit this code
32:44:15
and our code beats 100% of all the other solutions which is pretty awesome and that is because this runs in 0 millconds
32:44:23
but anyways this is a beautiful solution and a good introduction towards the dynamic programming.
32:44:38
Hello friends, we are still not employed by fang company. So let's not stop lead coding till we get there. The problem we are going to do today is actually asked
32:44:44
in lot of top tier IT companies and if we look at the recent data it has been asked in Amazon 20 times, Apple eight
32:44:51
times, Facebook two times, uh Google six time. So needless to say that this is a
32:44:57
really important problem. Uh so I hope you provide your utmost attention. Uh
32:45:02
this is the outline on how we are going to solve this uh and the things I'm going to cover in this video. So first
32:45:09
we will understand the problem statement. I will be creating a brute force solution. Uh then we will build an
32:45:14
optimal solution with dynamic programming and uh at the end I'm going to show the Java code for this one.
32:45:24
Basically uh this is a lead code medium problem but in my opinion it should be a lead code easy problem because it's not
32:45:30
very difficult to understand. But the thing is its concept is really important. uh that helps you build the
32:45:36
conceptual knowledge of dynamic programming which you can use in bunch of different uh problems and lot of fang
32:45:43
companies loves to ask this kind of questions. So if we understand the problem statement uh basically we are a
32:45:49
professional robber uh and we are planning to rob houses in each street. Now the thing is uh the way houses are
32:45:57
mentioned uh in the street is that every single house has some amount uh in that
32:46:03
particular house but the only condition we have is if we rob one house we cannot
32:46:09
rob the house that is exactly adjacent to it. So suppose we decide to rob this house. Uh if we rob this house which
32:46:16
means that we cannot rob this house or this house and uh we can again if we
32:46:24
want we can again rob this one. Uh so that option we have and the our aim is
32:46:30
to maximize our profit. So basically we are given an input array nums uh that
32:46:36
shows that for every single house how much uh amount of money is presented over there and we need to see that what
32:46:43
route can we take which maximizes our input or the amount of money we can steal and uh we need to provide show
32:46:50
that in the output. So let's uh try to understand this with an example. So
32:46:56
basically over here we are given the values as 1 2 3 and 1. So notice that
32:47:02
the maximum uh amount we can uh steal is basically if we go down this path. So if
32:47:10
we start with the first house and then not then we can't use the we can't rob the second house but then we drop the
32:47:17
third house and uh the sum of these two would actually become four and this would be our answer.
32:47:26
So for the brute force we are going to solve the same problem. Uh basically one way to uh understand the brute force
32:47:33
approach is that at every single position initially we are at zero location. So if we just make all the
32:47:40
possible pairs uh which we can create where we can rob houses basically that
32:47:47
would be our solution. Let me show you how. So initially at zero position now we have two options. Either we can
32:47:53
select the value number one or two. So either we can select the first value or
32:47:58
second value. Uh and these are the subsequent values. Now at this position
32:48:04
one we again have two options. Either we can rob the third house from here or we
32:48:10
can skip the third house and we can also rob the fourth house if we want. So the
32:48:16
two choices we have over here is either we go down this path or we go down this
32:48:21
path. And uh at this house number two, we only have one option. We can't rob
32:48:27
this one or we can't rob this three. So we can only rob this one. So
32:48:34
uh the only choice over here we have is actually one. And now we just do the sum of all the values. So uh for this path
32:48:46
the sum we would get is four. uh for this particular path
32:48:52
the sum we would get is two
32:48:58
I just put it in a box so it's easier to differentiate and down this path the
32:49:04
maximum sum we can achieve is three so if we compare these three elements we
32:49:09
can clearly see that four is maximum so we simply return four now brute force solution works but the problem with this
32:49:15
one is that we need to create every single pair And uh in order to generate pair
32:49:21
essentially at every single position we have two options that whether we need to
32:49:27
keep this value or we need to we do not need to keep that value and that
32:49:33
eventually would bring a lot of different values in our graph and uh on
32:49:40
the number of decisions we can make which means that the time complexity for
32:49:45
brute force approach would be you guessed it correctly 2 to to the power of n where n is basically whatever the
32:49:52
number of inputs given over here and you guessed it correctly also I
32:49:59
already gave it away u but we are going to use dynamic programming over here and let me show you how we can use dynamic
32:50:05
programming to solve this problem we are going to have use a custom example and I have already mentioned it bunch of times
32:50:11
that it is really important to have your own custom examples uh that shows that you can think outside of the box. So
32:50:19
over here initially uh we are at this position value number two. Okay. So what
32:50:27
we can determine is that initially at this position if we were given only one
32:50:33
house what is the maximum amount of value we can steal from this particular
32:50:39
house? Of course the answer is pretty simple. We can only steal whatever we are given right because we we are only
32:50:44
given just one house. So initially at this point suppose if we create an
32:50:50
additional data structure that keeps the track of what is the maximum amount of
32:50:56
money we can steal up for any element then it becomes then our decision making
32:51:03
will become easier and we would be able to choose that what path we want to take. Uh so let me show you by an
32:51:10
example. So initially at this position value number two the maximum amount we can drop will only going to be two
32:51:18
because there are no other values before that. So this is the maximum amount we can drop so far. Okay. Now this at value
32:51:27
number four the maximum amount we can rob is actually
32:51:32
up until this point it's only four because we can't use two uh when we are
32:51:39
robbing four uh when we if we choose to rob this second house if we choose to
32:51:44
rob this one we can't use it uh we can't basically use this first house so uh we
32:51:51
know that for the first two values these are the maximum amounts we can rob. Now
32:51:57
we are at this position number three. So at this position number three we have two options choices are pretty simple.
32:52:04
Either whatever the value maximum we have so far over here which means that so far the maximum value we have is four
32:52:11
or whatever the previous maximum value we had plus whatever value we currently
32:52:19
are at. Because remember if we decide to rob this house number three uh basically
32:52:26
we can we still have the option to rob house number two. We can't rob house number four. Uh so
32:52:33
up until this value number five the maximum we can rob so far is actually uh
32:52:40
five. Why? Because we can we check that okay up until this point what is the
32:52:46
maximum that previous element has dropped? basically like one house before this house has robbed and that that
32:52:53
maximum value is two. So I can do 2 + 3. So maximum I can rob under up until this
32:52:59
point is actually five. So okay we have this knowledge and up until this value
32:53:04
the maximum we can rob is four. Now let's forget about this one for now because anyways at any given time we are
32:53:12
only concerned with the house that are adjacent to each other. Now we are at this position number nine. So what is
32:53:19
the maximum value we can rob up until this point 9? Well, the answer is quite
32:53:24
simple. We check that okay what are the two values before this 9. So this is
32:53:31
five which means that if we decide not to rob rob this house the maximum we
32:53:38
have robbed so far in this uh subarray is actually five.
32:53:45
But how do we decide that whether we want to keep this nine or not? Well, we
32:53:50
just need to apply the same logic. The house that is adjacent to 9 before
32:53:58
that what is the maximum amount we have found? So the maximum for that is 4 and
32:54:03
we do 4 + 9. So 4 + 9 is 13 which means that up until this point
32:54:09
the maximum we can get the amount is 13 which is definitely greater than 5. So
32:54:14
it is in our interest to keep this pair so far. Now we can forget about this
32:54:20
four because we already calculated its value over here. And now
32:54:27
at this next value, value number 11, again we have two choices. Do we want to
32:54:33
keep 11 or not? So again we do the same thing. We compare 11 with whatever value
32:54:39
we have over here. We do first of all we do sum of 11 + uh this five. So we do 11
32:54:45
+ 5. Okay, this one is 16. So which is greater than 13 which means it is in our
32:54:52
interest to keep the value 11. Uh so again we are going to have 16 over here.
32:55:00
We can forget about this one because we already calculated its value. And uh
32:55:07
yeah, so we are now the two choices we have is 16 and 13. And this value number
32:55:12
two, we need to check two items. Uh so value before that this is 16 and this
32:55:18
one is 13. So we do 13 + 2 15. So, so
32:55:23
far if we decide to keep this value number two in our uh list of houses that
32:55:30
we are planning to rob the maximum value we can achieve so far is 15. U but the
32:55:35
thing is we have already found a better option than this 15 and which is 16. Uh
32:55:42
where if we decide to rob these three houses we will get the optimal uh
32:55:47
answer. And notice that every sing we were able to complete this whole iteration in just single uh it we were
32:55:56
able to complete this whole calculation in just a single loop. uh because we are keeping track of uh whatever the
32:56:03
elements we have calculated so far which is the exact use of dynamic programming and we are not using more than one
32:56:10
element at any given moment which means that our solution is actually quite helpful and uh very perfect. So let's
32:56:19
calculate the time and space complexity and basically this would be the optimal solution. So time complexity as you have
32:56:25
guessed it correctly it's actually big of n because we are completing everything in just one single iteration.
32:56:30
We don't need to do multiple rounds of uh checks and the space complexity uh we
32:56:37
have is actually bigo of one. It's actually constant time because notice that at any given moment the maximum
32:56:44
value we are keeping track of is just couple of elements. uh and uh we kept on updating our elements that whatever we
32:56:50
are keeping track of which means that uh we are not using that much space we are not creating an additional array to
32:56:57
store all the values okay let's create two elements
32:57:04
uh we'll name it rob one and uh initialize it to zero and we'll create a
32:57:10
rob two we'll also initialize it to zero and we'll have another variable. We'll
32:57:18
just name it max to keep track of maximum element that we have calculated so far. And now let's run a for loop.
32:57:26
Inside the loop, first of all, we'll calculate that whether we have achieved the maximum value or not. So max would
32:57:32
be
32:57:41
so whatever value we have at rob one plus
32:57:47
whatever value we are currently at. So this is one option or whatever the value
32:57:54
of rob two we have because notice that the rob two element is actually right
32:57:59
adjacent to this e element. And now we need to update the values of
32:58:04
rob one and rob two. So rob one will actually become whatever value of rob 2 we had because we are updating it every
32:58:12
single iteration and rob 2 will actually become the maximum value we have found so far.
32:58:19
And uh yeah I think this this should be our uh solution and at the end we will
32:58:25
return uh the max element. So let's try to run this code. Okay our
32:58:32
solution seems to be working. Let's try to submit it. Oh okay. Yeah our solution is actually
32:58:38
zero runs in 0 millcond and it's 100 times faster than all the other solutions. thing is this is not true
32:58:46
because we are given a limited number of test cases. We are computing everything
32:58:51
in just constant time. So that's why it's showing us 100% faster.
32:59:05
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Uh today we are going to do a very important
32:59:11
problem. Houser robber 2 and this is actually an extension of original house robber problem. I have already solved
32:59:17
the house robber problem over here. So you can check out that video and I highly recommend that you check out that
32:59:23
video before coming to coming onto this problem. Uh typically in any interview
32:59:28
this problem is actually going to be asked as an as a follow-up question after they have originally asked this
32:59:34
house robber problem. And that is why if we see the number of companies that have asked this question recently, it's
32:59:39
actually quite small compared to what we are used to seeing for the other companies. But thing is still Amazon and
32:59:45
Google have asked this recently. Even Microsoft asked this just a little bit sometimes back and also few other
32:59:51
companies have asked this. So this is a lead code medium problem
32:59:58
and uh basically the problem statement uh is saying that we are professional
33:00:03
robber and we are planning to rob houses along a street. Now the catch over here is that the all the houses in this in
33:00:10
this given street are actually arranged in a circular fashion and also there there is one more constraint that we
33:00:17
cannot uh rob two houses that are adjacent to each other. If we rob two houses that are adjacent to each other,
33:00:24
uh basically police is going to be called and we will be caught. Uh so this is a constraint that we have to look
33:00:30
into. And our uh our motive is to collect or gain or rob as much money as
33:00:36
possible without being caught. So let's try to uh let's try to see a pictorial
33:00:43
representation. So basically all the houses in the street are actually placed
33:00:48
like this. So suppose if we consider that this is our first house. Uh
33:00:53
actually the first house is also neighbor of the last house uh in the
33:00:59
given street because all the houses are stored in a circular fashion. And now since the houses are stored in a
33:01:05
circular fashion that is one more thing that we need to consider and also we cannot rob two adjacent houses. So
33:01:11
suppose if we decide to rob this house we cannot rob this house or we cannot rob this house. So the first example we
33:01:18
are given is the houses are uh placed like this and uh these are the amount of
33:01:25
money that is uh at each house. So basically since there are only three
33:01:30
houses we can only rob one house and we need to select the house with maximum money. So it's pretty simple over here
33:01:36
that if we select this house we get the maximum money and if we rob the house with value number three we can't rob
33:01:42
these two houses because because they are adjacent to each other. Uh in the second example the houses are stored
33:01:48
like this 1 2 3 and 1 and uh the most
33:01:55
amount we can collect over here would be if we rob this house and this house. So
33:02:00
in that case the amount of money we would collect would be four and uh we won't be able to rob these two houses
33:02:06
because they would be adjacent to each other. So we already know the brute
33:02:12
force approach. Basically the brute force approach is to make every single uh pair uh and check out all the
33:02:19
possibilities to see how we can uh find the answer. But the thing is there is no point in go exploring brute force
33:02:25
approach over here. Uh I'll directly go to the most optimal solution that we are
33:02:30
going to achieve using dynamic programming because this is an extension of uh house robber one. If you want to
33:02:37
get get more information about the approach you can check out that video first.
33:02:44
So for the optimal solution we are going to use a custom example and this this is very important to use custom examples
33:02:51
because it shows that you can create test cases on your own and uh this is a really good skill to have in actual
33:02:56
computer world. So suppose the number of houses we are given over here are in this fashion and uh let's try to draw
33:03:04
them in a circular manner. Now basically we can use the same
33:03:12
solution we were using in uh house robber one because remember in in house
33:03:17
robber one what we were doing we were just simply going through whatever the input we had and we were just keeping
33:03:24
track of what is at any location what is the maximum amount of money we can rob
33:03:29
up until this element u by checking the previous values we are essentially going
33:03:35
to do the same thing over here but just in a little bit different manner. Because uh in the house robber one
33:03:41
problem we were considering the whole thing because they were all the houses were placed in a straight line. So we
33:03:48
were able to consider them like that. The thing is over here the additional constraint is that whatever the last
33:03:54
amount or the last house is is actually neighbor of the first house which we can
33:03:59
see over here that these two houses are neighbors of each other. Which means that if we at any point decide to rob
33:04:06
this house, we cannot rob this house or vice versa that uh if we decide to rob
33:04:13
this house first house, we need to make sure that we do not rob this house. So
33:04:18
the answer is actually quite simple. Rather than treating this as a circular
33:04:23
uh street, why don't we just uh run two functions? So basically uh in during the
33:04:30
first uh uh loop during the first uh iteration we are going to check the
33:04:36
first sub problem and let me show you what I mean.
33:04:42
The additional constraint we have over here is that if we consider this house uh it is guaranteed that we cannot use
33:04:47
the last house or if we use the last house it is guaranteed that we cannot use the first house. So since we know
33:04:54
that this condition exist why we are simply going to uh do calculation twice.
33:05:00
In the first calculation, we are going to check between these houses that what
33:05:06
is the maximum amount we can rob. And during the second uh loop, we are going
33:05:13
to check that amongst these houses what is the maximum amount we can rob. And
33:05:18
then we just need to compare that what is the maximum value we have found across both the loops. And whatever the
33:05:25
maximum value we find, we just uh push it. we just submit it as uh our answer.
33:05:31
So let's iterate over the uh entire problem.
33:05:39
Okay. So these are the two loops that we are going to iterate over. So let's calculate the result for the first uh
33:05:46
loop. So for at the first position, the maximum amount we can rob so far is only
33:05:51
going to be one. And at the second house, the maximum amount we can rob is only going to be two because we cannot
33:05:57
rob the first house. Now the for the third house we have two options. Either
33:06:03
we keep whatever the value of two we have or we keep the value of 1 + the
33:06:09
third house value and we check we see that whatever is the maximum value amongst these two we are going to keep
33:06:16
that. So 1 + 15 is going to be 16 and of course 16 is greater than 2. So we are
33:06:21
going to say that up until this house number three the maximum amount we can rob is 16. Now we are at the fourth
33:06:28
position. Now over here the maximum amount we can rob is actually two. We
33:06:34
have two options. Either we can rob 16 units or we can do 2 + whatever value at
33:06:41
house number four we have. So 2 + 11 is actually 13 which is less than 16. So
33:06:47
even up until this point the maximum amount we can rob is still going to remain 16 and not 13 because uh
33:06:55
definitely 16 is greater than greater value. So it is in our interest to uh
33:07:00
keep this value 16. Now again we are at this position three and also notice that
33:07:06
at any given location we are only considered with values that are of
33:07:11
previous two houses that we have calculated over here. We don't need to consider all the values because we are
33:07:18
already adding them up and we are only keeping the maximum values. So this works in our favor.
33:07:26
So at value number three uh the maximum we can achieve is either 16 + 3 or 16 by
33:07:35
itself which is this 16 or 16 + 3. So of course 16 + 3 is going to be greater. So
33:07:40
we are going to store 19 and we don't care about these values anymore because we already have the latest values so
33:07:47
far. Now at value number six the maximum
33:07:52
we can find is going to be 16 + 6 or
33:07:59
19. We need to select whatever is greater. So 16 + 6 is 22. This is the greater value. So we are going to keep
33:08:06
this and we don't care about 19. So we can see that at the end of this first loop the maximum value we have found so
33:08:13
far for this particular uh set of houses is 22. Now let's repeat the same process
33:08:21
for the second uh uh loop. So in the second loop
33:08:27
for the first position the maximum we can rob so far is two. Uh at the second house the maximum we can rob is 15. Now
33:08:35
over here the maximum we can rob is either 2 + 11 which is 13 or 15. So of
33:08:41
course 15 is greater. So we are going to keep 15 over here. Now at this position
33:08:46
number three we can either do 15 + 3 or compare it with 15. So 15 + 3 is 18. So
33:08:52
we are going to keep 18 over here. Now at this position we consider these two
33:08:58
values. So either we do 15 + 6 which is 21 or we check with 18. So 21 is
33:09:04
greater. So of course we we are going to keep this one. And now at this last position we check that whether 21 or 18
33:09:12
+ 10. So of course 18 + 10 is 28. So we are going to keep that and we are we do
33:09:17
not consider about 18. So after this entire loop the maximum value we have
33:09:22
found so far is 28 and the maximum value we had found over here was 22. So our
33:09:29
job is pretty simple. We just just need to see that whichever value is actually greater we simply return that and in
33:09:35
this case 28 is greater than 22. So 28 would be our answer and we just return
33:09:41
that value. Uh this is a very good solution. We are building it on top of
33:09:47
whatever we have solved for house uh robber one and because we are basically
33:09:52
using the same solution we are just changing the scope of uh up until what
33:09:58
points we are using this solution. So just keep that in mind. And uh if we
33:10:03
calculate the time and space complexity uh the time complexity for this one is going to be big of 2 n uh because we are
33:10:12
running two loops uh 0 to n minus one and n uh 1 to n. Uh so if we gener
33:10:19
generically mention this it actually becomes it becomes big of n. And uh if
33:10:25
we calculate the space complexity the space complexity would be big of one
33:10:30
because we are apart from storing couple of parameters we are not using any additional space. So that's why we we
33:10:37
are able to run this in a constant time uh sorry constant uh space.
33:10:44
Okay let's start creating parameters. So we are going to need two parameters rob one and rob two. And we are going to
33:10:51
initialize both to zero.
33:10:58
We'll also need two parameters to store to maximum values. So we'll name them max one and max 2. And max one we will
33:11:06
initialize it to uh the zero house and uh max 2 we can actually initialize it
33:11:12
to uh zero because we are not going to consider the first house and we are keeping the max one as zero because in
33:11:19
case we are given the condition where we only have one input so we can simply return that. Now let's run a for loop
33:11:26
starting from the first house. So I =0 to I is less than uh length minus 1
33:11:34
I ++ okay over here we are going to calculate max one. So max one would be uh maximum
33:11:43
value amongst rob 1 plus uh the current
33:11:49
number we are at or uh the value of rob
33:11:54
two and we also need to update the value of rob one and rob two. So rob one would
33:11:59
actually become rob two and uh rob two will become the maximum value we have
33:12:05
found so far. Now once we are done with this loop, we need to reset the values
33:12:10
of rob one equal to zero and rob 2 equal to zero because we are going to use them
33:12:15
again in the second loop. And uh we are going to create another for loop uh i= 1
33:12:23
and we are going to set up i is less than. So nums do.length
33:12:31
i ++. Okay. And essentially we are going to use the same conditions. Uh by the way
33:12:38
we this would be max one. We are going to use the same conditions. So we can just reuse the code. And uh we are going
33:12:47
to rather than calculating max one we would be calculating max two. So let's do that. And uh after the second loop we
33:12:55
still we simply need to return whatever the maximum value we have found amongst max one and max 2.
33:13:09
And uh this this should be the solution. Now notice that I'm running two loops over here. But the thing is uh an
33:13:15
efficient way to do this is to create a function and uh function would uh intake
33:13:20
the parameters like start and end value and you can just repeat this process. So that would be an uh efficient way to do
33:13:28
do this code as well. Let's try to run this. Okay, seems like our solution is working. Let's try to submit the code.
33:13:41
Hello friends, we are still not employed by fang company. So let's not stop late coding till we get there. Today we are going to do a very important lead code
33:13:47
problem, unique parts. And as you can see that this question has been asked in Google, Facebook, Amazon, Apple,
33:13:52
Microsoft, Bloomberg, all huge gigantic IT companies. So I highly urge you not to miss this video and uh try to
33:13:59
understand the problem as as thoroughly as possible. Um this is going to be the framework for the video. We are going to
33:14:05
understand the problem. We are also going to find a primitive approach. We are going to find the optimal solution and we will write a Java code for the
33:14:10
optimal solution. This is a lead code medium problem. We
33:14:15
are given that there is a robot and an M crossN grid and robot is initially located on the top left corner. Now
33:14:23
robot tries to go to the bottom right corner. So this is the last place where robot wants to reach and uh at any given
33:14:30
moment robot can only make one move. It can either go down or it can go right at any point in time. Uh no other ways it
33:14:37
can make. So in the problem we are given this m and n and we need to find that
33:14:42
how many distinct unique paths can robot take to reach to the bottom right corner or its final destination. So suppose our
33:14:51
given m is equal to 2 and n is equal to 3. If
33:14:58
suppose our m is equal to 3 and n is equal to 2. This is one of the test
33:15:03
cases. So if we see if we draw it on the board it would look like this.
33:15:12
This is where the robot is initially. So I'll just mark it as R. And this is the
33:15:18
destination that robot wants to reach the bottom right corner. Now we know we need to find that how many unique paths
33:15:24
exist. So let's see that how many unique paths can we make and at any given moment robot can either go on the right
33:15:30
side or down. It cannot make any other steps. So let's see that what are the possibilities. So this is one
33:15:37
possibility. So this is one path. I'll just mark it somewhere. Now this is second path.
33:15:46
I'll also mark it somewhere. So this is second path. So have we exhausted all possibilities? No. There still exist a
33:15:52
third path and the third path is like this
33:15:59
1 2 1 and apart from these I we cannot make any uh any more paths. So
33:16:07
essentially we are existing all the exhausting all the possibilities and we can return that for this given m and n
33:16:14
the number of unique paths can be three. Now I hope that this uh makes problem statement more understandable. Over here
33:16:21
initially we are given an example of m is equal to 3 and n is equal to 7. Uh and the number of unique parts they get
33:16:27
is 28. But the thing is this would be too such a long uh uh example so I'm not going over it.
33:16:36
Okay, let's understand this uh with a custom example. So suppose our m is equal to 3 and n is equal to 3. So we
33:16:42
would have a grid that looks like this here. This is our robot. This is our
33:16:48
destination. Now we are going to calculate that at to in order to reach to any element how many unique paths we
33:16:54
can take. So suppose if you want to reach to this element how many unique paths we can take? We can only take one
33:17:00
unique path and that would be to take this right step from here. we cannot take any other step. Same goes for this
33:17:06
element that we can only have one unique path and that would be to take two right steps from here. Uh we cannot reach to
33:17:13
this point any other way. Same happens for these two elements as well that we can only take one step down or two steps
33:17:20
downs to in order to reach to these two elements. The thing is there cannot be any other unique path if we want to get
33:17:26
here. But thing is when we get to this middle points uh something interesting happens and the interesting thing is
33:17:33
suppose we want to reach to this point how many unique paths we can take. Well we can take two unique paths. We can
33:17:39
take one unique path to reach to reach over here and then over here or we can take one unique path to reach over here
33:17:45
and then again reach over here. So we can say over here we took two unique paths. But the thing is if we just see
33:17:52
that what are the entry points to get to these this point actually there are only two entry points to get to this point.
33:17:58
One entry point is that we can if we somehow get to this point, we just take
33:18:04
one step downwards, we we come over here. Or if we somehow get to this end point, if we take one step on the side,
33:18:10
we reach over here. Which means that whatever the unique paths we have at these two locations, if we just sum
33:18:17
these two up, it will give us the number of unique paths we can we can take to get to this point. So let me show you by
33:18:24
by another example. Now again let's consider this element.
33:18:31
So in order to reach to this element there are only two ways we can reach to this element. We can either take one
33:18:37
step from here or we can take one step from here which means that whatever the number of possibilities we have over
33:18:44
here that once we get to this point we will be able to come to this unique path. Okay. So that is a given. Same
33:18:51
goes over here that uh no matter how many number of possibilities we have to come to this point if once we are at
33:18:57
here we are guaranteed that we can come to this point. So in order to reach to this point the only possible ways are
33:19:05
this one and this one. So if we sum these two we will find the number of unique unique ways we can reach to this
33:19:12
element and in this case it would be three. If we continue down the same path for
33:19:19
this point, uh we can take three distinct paths to reach over here. And
33:19:25
in order to reach to this destination D, we can take 3 + 3 six uh unique paths to
33:19:30
get to here. And this actually becomes our answer.
33:19:37
Okay. So based on our previous explanation, we know these things. So if we see now we need to see that how can
33:19:44
we use dynamic programming to solve this problem. And the reason we are choosing dynamic programming is because at any
33:19:49
single location we are computing that whatever the previous two results that we have already calculated and we are
33:19:55
using them to calculate the next values. So that pretty much uh indicates that we
33:20:01
need to use dynamic programming over here. Now let's take a 2x2 matrix and uh
33:20:08
we'll just provide the index values. So index values would be 012 012 and we
33:20:13
would name this matrix as DP to refer dynamic programming. Now the thing is if
33:20:18
we want to find out the value at this position we know that it would be sum of these two elements. So mathematically we
33:20:26
can write them like this that DP of 1 one because this this is one and this is
33:20:33
one is actually equal to DP of 0 1 that
33:20:39
we have already calculated which is this value plus DP of 1 0
33:20:47
which is this value and sum of these two will give us this value. So generically
33:20:53
we can actually write them like this that at any given location DP of M and N
33:21:00
would actually become DP of M -1 N plus
33:21:06
DP of N and N minus one and this would be our
33:21:14
recurrence relation for dynamic programming and I already explained that why are we choosing dynamic programming
33:21:20
and our aim is to find that how many distin ways we can reach to this destination. So this destination would
33:21:25
actually become uh dp of 2 over here and if we compare it with
33:21:33
whatever m andn is given uh this actually becomes the value over here
33:21:39
this would become the dp of m minus1 and
33:21:44
n minus one. So we start our calculation like this and eventually we would reach
33:21:51
to this point and we just need to return whatever we have found over here and this would be our solution. So we can
33:21:59
just create two loops one loop iterate over the column one loop iterates over the rows and eventually we will reach
33:22:06
this end point we return this this becomes our solution and this is a very efficient dynamic programming solution.
33:22:13
uh any fang companies Facebook, Google, Amazon whatever they would be happy to
33:22:18
hire you immediately. So now let's see that uh what would be the
33:22:24
time and space complexity. So time complexity would be big of m * n because
33:22:30
we need to iterate over this entire grid. So that's why it's because of M *
33:22:35
N and space complexity. Remember that we are creating this additional DP array uh
33:22:41
which is 2x2 matrix and we are giving the size as M and N. So space complexity
33:22:48
would also be big of M * N and this would be our solution. Now let's move on
33:22:53
to coding. Okay, first of all, we'll create a two-dimensional array and we'll name it
33:23:00
as DP and uh we'll provide the length as M and
33:23:07
N. Now we'll have to create our base case. So we will fill our uh two-dimensional
33:23:14
array and this is the way to fill a two-dimensional array.
33:23:22
And over here
33:23:34
now we will create two for loops and uh we'll start with i is equal to 1 and j
33:23:40
is equal to 1 because we already have cases for zero while i is less than m i ++ +
33:23:53
j = 1, j is less than n.
33:24:03
Okay. Now we will provide our recurrence relation. So DP of I and J at any
33:24:11
location is equal to DP of I -1
33:24:16
J plus BP of
33:24:22
I J minus one. And uh yeah, this is pretty much it.
33:24:29
This should be working. So now let's uh return
33:24:37
let's return uh dp of m minus one and g n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n minus one.
33:24:51
Let's try to run this code. Oh, it should be arrays.fill. Small
33:24:59
error. Looks like our solution is working. Let's try to submit the code. Okay, our solution is actually runs in 0
33:25:06
millisecond. It's 100% faster than all the other submissions, which is pretty good. And uh I'll be posting this in the
33:25:13
comments. You can check it out from there. Thank
33:25:32
Hello friends, I'm a cloud solutions architect who like to solve lead code problem and today we are going to solve a very interesting lead code problem
33:25:38
called Pascal's triangle. Now if we see some of the popular companies who have already asked this question, there are companies like Amazon, Bloomberg,
33:25:44
Google, Apple, Microsoft, Goldman Sachs, TCS, Uber, Facebook and Infosys. So
33:25:49
that's why I'm paying my utmost attention. I hope you also enjoy the video.
33:25:55
So this is a lead code easy problem and also a very well-liked problem. Basically we are given an integer array
33:26:01
called number of rows and we need to return the first number of rows of a Pascal's triangle. Now the biggest
33:26:07
question in this problem is what the heck does this Pascal triangle means? Uh they have actually drawn a diagram over
33:26:14
here and you can try to understand it using this but I'm actually going to show you an animation that what a Pascal
33:26:20
triangle is. Okay. So now we are actually trying to create the Pascal's triangle and for
33:26:26
that I found a definition online. If we read through the definition this is saying that okay in order to build the
33:26:32
triangle or Pascal's triangle basically we need to start with one at the top and then we need to continue placing numbers
33:26:38
below it in a triangular pattern. Okay that's a given fact. Second thing it says is that each number in the numbers
33:26:46
is the combination of the two numbers above it added together. Let's try to
33:26:52
understand this with an example. So over here we are trying to build a Pascal triangle with six different rows and I
33:26:57
have drawn six rows over here. After marking their numbers now based on this
33:27:03
definition, okay, first value has to be one. So we are starting the first value as one. Right? Now what it says is that
33:27:09
every single number is the number that is combination of two numbers directly
33:27:14
above it. Now if we see this first box, this first box is only connected with
33:27:20
one box at the top. So definitely the sum of this value is going to be that value by itself. So this is also going
33:27:26
to be one. Same way this value is also going to be one because both of them are only connected with one box above it.
33:27:33
That is the key phrase that one box above it. Same way if we try to take a look at this box, this is also connected
33:27:39
with just one box. So because of that we are also again going to add one over here. But when we reach to this
33:27:45
particular middle box, things becomes interesting because if we see this above part, this above part is actually
33:27:51
connected with two different cells. So because it is connected with two different cells, we are actually going to do sum of these two. So 1 + 1 is
33:27:59
going to be two over here. And again remember this 1 + 1 is coming by sum of these two values. Why? Because this
33:28:05
particular cell is connected with both of them. Now if we go back, okay, this one will always be one because there is
33:28:11
only one element. Now again this is also going to be one because it's only connected with just one element. But in
33:28:17
this case this particular element is connect again connected with two elements. So we are going to do the sum
33:28:22
of it. So if we do sum of it we get the value three. Again this is also connected with two elements. So sum is
33:28:28
going to be three. And this is only connected with one element. So sum is going to be one. Same way we keep on
33:28:33
repeating for the row number five. So again this is going to be one. Now this is going to be sum of these two which is
33:28:38
which becomes four. Now this particular element is going to be sum of these two elements which is going to be six. This
33:28:44
element is going to be sum of these two which is again going to be four and then again one. Keep on repeating the same
33:28:50
process and this is how all the rows are being formed and this is a Pascal
33:28:56
triangle. So in this case we created a Pascal triangle with six different rows and we need to provide this as the
33:29:02
answer. So as an input value we are only given this element that how many numbers of rows we need to create and in the
33:29:08
answer we need to return this one and now the answer for these is needed to be returned in a specific format uh so that
33:29:16
our program can understand and the format looks like a list of lists. So first we create an array list and every
33:29:22
single value represents all the values inside this particular row. So currently the first row only has one element. So
33:29:27
we are only going to add one element over here. Now for the second row it has two elements. So we are going to add two elements over here. Again for the third
33:29:35
row it has three elements. So we are going to add all three elements over here and so on and so forth. We keep on
33:29:40
adding all the values and in the end we return the answer. And this is the answer that is expected in this case.
33:29:47
Right now basically I think this makes understanding more much more clear that what a Pascal triangle is.
33:29:55
So now I have created a Pascal triangle uh that is needed for like seven rows right and for seven rows definitely we I
33:30:02
already showed you that how we are we are populating all the answers that first this value is 1 this value is 1
33:30:08
one then again this value is 1 2 1 okay so this is the Pascal triangle that we
33:30:13
can create for seven rows but if you observe the answer basically first of
33:30:19
all we need to define that how the answer is being generated over here the answer for any single cell is dependent
33:30:25
on its like further value. Same goes for any single possible cell that that cell
33:30:31
is made up or comprised of the two cells that are exactly above it that it is
33:30:36
being connected to. Now that is okay that is one property. Uh second property
33:30:41
is that in order to generate any single cell how can we find its value? Well, we
33:30:47
can simply find its values based on that if we have store somewhere to store the
33:30:52
value of the previous row. If we have that value, definitely we can able to generate the answer. And the thing is
33:30:59
because any single result is based on the results of its previously computed
33:31:06
values. We are actually reusing the same value that we have already used. Which
33:31:11
means we are actually going to use the most beautiful concept inside the computer programming which is dynamic programming in this case. Now for this
33:31:18
dynamic programming what we need we need a base case. So base case what is going to be uh that is already given in the
33:31:24
definition of Pascal's uh triangle that the first triangle is always going to be one. So that is okay that is a given
33:31:31
fact right that this becomes our base case. Now based on this base case I just showed you that we are able to generate
33:31:37
any single triangle of any single length. In this case the length was seven. So we were able to quickly
33:31:42
generate that. So the logic we are going to use in this case is that okay first we calculate the first value. We get the
33:31:49
answer as one. Right? We store that answer. Now for the second column okay first what are the things we know about
33:31:55
the second row. The thing we know about the second row is that there are going to be two elements. Right? Now for this
33:32:01
two elements what is the thing we have? we the thing we have is that we we have one element that is present before that.
33:32:08
Okay. So in this case uh the first element is only possible to be connected
33:32:15
with just one element. So since we have already saved that answer over here we can simply leverage that and same goes
33:32:21
for the second element that that can only be connected with one element. So we can also store that answer over here.
33:32:26
Okay. Now we are at the third position. Now for the third position what is the logic? So the first value is always
33:32:32
going to be one. So we can by default mark the first value to be one and also the last value will always be one as
33:32:38
well. So we can also mark the last value to be one as well. Now for the middle values what we are going to do is okay.
33:32:44
So currently if we see the index position of this middle value the index position is going to be one. Why? Because there are three elements. So in
33:32:51
a typical array the index position is going to be like 0 1 2. So this is like the first index position. Now we are we
33:32:57
already know we are trying to populate this third uh value and for the third row first one value is one that is a
33:33:03
given fact right? Now for the second value or the value located at index number one how can we calculate that? We
33:33:10
can simply calculate that okay this is index number one right. So this index number one has to be connected with the
33:33:17
previous value of index 0 and index one. And that you can see over here that this
33:33:23
was connected with like index value zero and this was in index number one and that is how this is connected. So all we
33:33:29
will have to do is just do the sum of them and that we can clearly found from the answer we have already stored over
33:33:35
here. So which is two and again the next value we will get is one. Uh now we need to create the fourth row. Okay. So for
33:33:42
the fourth row I'm not going to show you in the triangle. I'm just going to show you in the answer that how we will be able to generate that. So first value is
33:33:47
one. That is a given fact. We are trying to find four elements in this case. Now for the second element, second element
33:33:54
is located currently at like first index position. Right? So because the index
33:33:59
position is first, which means we will have to do sum of zero and first index position which is these two values. So
33:34:05
in this case the answer is going to be three. Again now for the second element. So this is like the third element inside
33:34:13
this fourth row and the second element on in terms of like index value. So okay
33:34:18
the index value for this one that we are trying to find is two which means we will have to do sum of 1 + uh two. So
33:34:26
okay what is the value located at index number one in the previous value which is this one two. Okay. And what is the
33:34:33
value located at index number two in the previous value which is one. So 2 + 1. So we get the answer as three. And since
33:34:39
we are only trying to populate four values the fourth value has to be one because that is we already established
33:34:45
that. So this is basically the simplest logic that we are going to use in order
33:34:50
to populate our answer using dynamic programming. If you don't still don't understand the concept, I suggest you
33:34:58
try to draw like any single uh Pascal triangle. It's pretty easy to draw and
33:35:03
then you would be able to calculate the values and basically using the dynamic programming this problem can be solved
33:35:09
really easily. If we see time and space complexity in this case the time complexity is actually going to be bigo
33:35:14
of n² where n is the number of rows that are given and uh that is the best we can
33:35:19
do. First of all we are going to create a
33:35:25
list of lists to store our answer. Now we are going to create our base case. So
33:35:31
base case is that always the first value is going to be the zero like the one and
33:35:38
uh so what we are going to do is we are going to add an a new entry over here. Now we have created our base case right
33:35:44
now as an input we are given the number of rows we need to perform. So what we are going to do is we are going to run a
33:35:50
for loop and inside this for loop we are going to run up until the we are going to start from row position number one
33:35:57
and we are going to go up until the point where we reach to the number of rows that we need to reach to. Now for
33:36:03
every single row we will have to create a new array list uh that we need to
33:36:08
input also at the same time for any single list we will actually have to require uh the previous list that we
33:36:15
have calculated right. So we are also going to create a new list to store the previous list and we are going to name
33:36:21
it as previous list. Now we have our value set up. Now first of all for the
33:36:26
new row that we are trying to add the entries we are actually going to assign the value one into it. And now we are
33:36:33
also going now we are also going to run another loop. Uh for this another loop okay let's just name the par parameter
33:36:39
integer J and we are going to start it from position number one. Why we are starting it with from position number
33:36:45
one? because we already filled out one value over here and this is going to run until we reach to the value of this uh
33:36:53
row that we are trying to reach. And now the core logic is actually quite simple. All we are going to do is for this
33:37:00
current row we are actually going to add the value and we are going to add the value based on the result of the
33:37:06
previous list that we got. uh and we are actually going to like get it using the
33:37:12
uh J minus1 value and plus we are going to get it uh like the J value and
33:37:19
basically this is the whole core of every single thing that we are trying to achieve. Now once we get out of this
33:37:25
loop remember the last value also needs to be one. So again we are going to do that uh in the end all we need to do is
33:37:32
just add this new uh row that new list that we have created in our answer. So
33:37:37
let's do that and in the end uh once we get out of the loop basically our answer should have been populated. So we can
33:37:44
simply return the answer. Now let's try to run this code. Seems like our solution is working as expected. Let's
33:37:50
try to submit this code and our code runs pretty efficiently and
33:37:56
uh it beats almost like 82% of the cases. Uh also in terms of memory consumption uh it beats lot of cases.
33:38:03
Now I forgot to mention the space complexity for this one. And the space complexity is actually going to be constant space. Why? Because anyways we
33:38:10
are creating like a new answer list to store the answer and we are only creating like couple of temporary list
33:38:17
over here. We are not doing anything extra. So that's why the space complexity is going to be constant space. And uh again as always I would be
33:38:25
posting this solution in the comments. So you can check it out from there. Thank you.
33:38:45
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we
33:38:50
are going to work upon a very important dynamic programming problem uh coin change and which in my opinion everyone
33:38:57
should do it at least two three four times until you get a real grasp of the concept on how to solve it. And uh let's
33:39:04
understand the problem statement. We are given an integer array of coins uh representing coins of different
33:39:11
denominations and we are also given an integer amount that represents the total amount of money that we want to
33:39:17
generate. Now we need to return the fewest number of coins that we can use
33:39:22
to make up to the amount that has been provided over here. And if the amount of
33:39:28
money cannot be repro uh reproduced, we need to return minus one. Let's try to understand this by an example.
33:39:36
So in the given example, the number of coins we are given is 1 2 and 5. And the
33:39:44
amount we are given is 11. So suppose so based on the example we
33:39:50
can clearly see that the most optimal way we can uh create this 11 is by using
33:39:57
5 + 5 + 1. So in general this sums up to
33:40:03
11. And if we see the number of coins it we are actually using uh three number of
33:40:09
coins to generate this value. If we look at the second example, uh
33:40:16
basically we are only given one coin, the value number two and the amount we
33:40:21
are given is actually three. So no matter how many times we use the the
33:40:27
number of coins to we cannot generate this amount three. So in that case we need to return minus one. While in this
33:40:35
case we would be returning three because we are using these three coins. So once
33:40:40
we have this clear now let's try to understand that what could be the different approaches we can take to
33:40:45
solve this uh problem.
33:40:50
uh the first approach that comes to our mind is actually to use a greedy approach where uh whenever we are given
33:40:58
the number of coins uh so let's take uh one of our own custom examples and we
33:41:03
also need to keep in mind that whenever you are solving or giving any fang interviews make sure to have your own uh
33:41:09
custom inputs because uh fang companies really like uh this kind of stuff uh and that
33:41:17
uh shows that you are able to think outside of the box and you can also create test cases on your own. So
33:41:23
suppose we are given an input like this and the amount we need to create is
33:41:29
actually eight. So in our greedy approach basically we at any given
33:41:35
moment for the given uh amount we will take the biggest coin that is smaller
33:41:42
than this amount and keep repeating till we reach this amount. Now let me show
33:41:47
you that why this approach won't work because if we see here uh the amount we have is eight and the biggest
33:41:54
denomination of coin we can create that is lesser than 8 is six. So if we take
33:41:59
this so let's create uh our answer where we keep track of how many coins we are
33:42:05
using. So we use six over here we take uh 8 to 6.
33:42:12
So we subtract 6 - 8 uh we get the remaining value is two. So since the
33:42:18
remaining value is two uh we cannot use these three coins anymore because they
33:42:23
all are greater than two. And if we were to subtract this coin from two we our
33:42:29
result would actually become negative. So we cannot use that. But we cannot you we can still use value number one. So if
33:42:37
we do that and if we use the coin number one because this is a greedy approach.
33:42:42
So we will add the coin number one to our answer as well. And so now the remaining value will be one. So again we
33:42:49
cannot use these three values but we can still use one. So we will use one. The
33:42:54
remaining amount is zero which means that we have reached our total amount of eight and we would add the value number
33:43:00
one over here. Once we do that essentially if we
33:43:06
calculate in the answer we are using uh three separate coins to reach the amount
33:43:11
eight. So our answer would be three in this case and we would return three. But
33:43:17
notice that this answer is actually not the lowest number of coins we can use.
33:43:23
Actually if we just use the coins three and five we can simply create this value
33:43:29
eight and uh our result in this case should actually be two not three. Uh so
33:43:37
greedy approach doesn't work at all. Now let's see what could be the next approach we we can take over here. Uh we
33:43:44
are given an input like this and uh we need to reach out to a
33:43:51
particular amount eight. So at any given point uh if we start basically start
33:43:57
calculating from zero and we will keep on making choices based on the number of
33:44:03
coins we have until we either reach to this value eight or our choices actually
33:44:10
becomes greater than 8. Until these two things happen, we can keep on making
33:44:15
choices given our uh coin denominations and based on that we can actually create
33:44:22
our own uh decision tree and in that decision tree whenever we reach at value
33:44:28
number eight we will keep track of the value keep track of the path and based
33:44:33
on that path we can calculate that what are the minimum number of iterations we have to make. So initially we are at
33:44:39
zeroth position. So from zeroth position we have four options that we can take.
33:44:44
Uh so let's take let's make four these four decisions
33:44:50
1 3 5 and six. Now at every single decision we still have four more
33:44:57
decisions that we can take to reach out to this value eight. So again at value number one we still have four more
33:45:04
decisions we can make. So let's do that. And again at every single iteration we
33:45:11
we still have four more decisions. And with every decisions we come closer to this value number eight. So initially
33:45:19
over here complete eight were remaining. Over here we are only dealt with
33:45:25
creating the value seven because we already used one coin. The remaining value would be seven. So over here the
33:45:32
remaining value would be one. The over here the remaining value would be two. Over here the remaining value would be
33:45:38
four and over here the remaining value would be six. And suppose we continue on
33:45:44
this path again we would still have four choices.
33:45:52
And notice that the remaining value we wanted to create was six which we are
33:45:57
able to achieve over here. So the sum for this particular path one again one
33:46:05
and then again six is actually eight which means that we have found a
33:46:12
potential route and if we see the number of coins we had to use we had to use 1 2
33:46:19
and three coins. So current amount um current answer we need to return is
33:46:26
actually three. And since we have found this route all the other routes if you
33:46:31
see the values would not reach to 8 and we can cancel out these values. And
33:46:38
basically because if we keep going on we will still have to make more decisions and the number of route will be will
33:46:45
definitely be greater than three. So we can start eliminating these routes and
33:46:51
we have one potential route over here. Again if we keep on going down this path
33:46:57
of three and keep making more decisions we would end up with an uh result that
33:47:02
would be greater than three or we would not reach eight at all. So we can ignore this. Again we can ignore this uh from
33:47:10
five. And at six uh we would still find a root
33:47:16
something like this where because notice even at six we still have four decisions we can make. So we can make e we can
33:47:23
choose either 1 3 or 5 or six and notice that only one is remaining over here and
33:47:29
we can select this one. So we would have another potential route uh starting from
33:47:35
one going to six and then again going to one that sums up to eight.
33:47:42
But again for this route as well we need to use three coins. So our answer will
33:47:48
still remain three and it won't be changed. But this is where we find
33:47:53
another answer. And now we have exhausted all the possibilities from value number one. So we can just ignore
33:47:59
all of this. Let's get rid of it. So we we have something that is more uh clear
33:48:05
and not so much congested. Now let's try to see that what would be the possibilities from this value number
33:48:11
three. So even at value number three uh the
33:48:17
remaining amount we have would be five. And at value number three we still have
33:48:22
four more possibilities that we can choose from 1 3 5 and six. And notice
33:48:29
that in all of these possib or these three possibilities uh we would not
33:48:35
reach eight. Uh so we would not reach basically the remaining value would not be uh zero
33:48:43
which means but if we get down over here five over here only five is remaining
33:48:49
and we directly have a coin five present at the decision tree three. And if we
33:48:54
calculate the route, the route would look like uh one and then two. So
33:49:00
basically we are only using one coin over here and we are using second coin over here. So we are only using two
33:49:08
coins to reach to this value eight. So we can simply update our answer that we
33:49:14
have found a new minimum value that can come up as our answer and we can uh set
33:49:20
the value as two. Now we can continue to search and keep on making more decision
33:49:27
trees and uh even for those nodes we will continue to making uh further down
33:49:33
decisions uh to see if we can find a better answer but we won't be able to find a better answer than two and
33:49:39
eventually we would have to return this value. So this solution in a way it works and it works uh as expected at
33:49:46
least we are getting the answer but the issue with this approach is that time complexity is actually so bad it's uh
33:49:54
not even in polomial time it's uh simply an exponential time and the time complexity suppose the amount we are
33:50:01
given if we consider it as m essentially until we reach this amount m we are at
33:50:08
every time keep on making multiple decisions based on the number of coins
33:50:13
that are given. So we can compute the time complexity as big of m to the power
33:50:19
of n where m is the given amount and n
33:50:25
are the number of coins that are present at any given moment. This is such a bad
33:50:32
time complexity that we even if we ask NASA to run this command they won't be
33:50:37
able to do it more more than up to a certain values and uh we need to find a
33:50:44
better approach and in the optimal solution we are
33:50:49
simply going to use just two golden words dynamic programming and let me show you how we can solve this via
33:50:56
dynamic programming programmatically And we are just like a rational person. We
33:51:03
are just going to think it uh in terms of intuitive intuitively that if we are given this problem just to solve on a
33:51:09
pen and paper how we are going to do it. Um and one approach is that we can
33:51:14
basically start from the value number zero. We can keep on reaching towards the amount we want to reach out to. uh
33:51:21
and for every single element that we have found, we will find that uh for 1 2
33:51:27
3 4 how many number of coins it took us uh to generate that particular amount.
33:51:33
And once we are sure with this value, whatever value we have generated the
33:51:39
amount for one or amount for two, we would be able to use this uh later down
33:51:45
the road. And let's take an example. Let's uh continue with our example and
33:51:50
see how can we achieve that. So uh we are given the example 1 3 5 and 6 and
33:51:57
the amount we want to generate is 8. So initially we would create an array of
33:52:07
amount from zero all the way up to amount of
33:52:14
eight. And we will initialize all the values by
33:52:20
any value that is higher than 8. So let's say 8 + 1. And now we will start
33:52:26
start with our solution. So so far all the values are actually 8 + 1 in this amount array. Uh and this represents
33:52:35
that these are the number of coins that are needed in order for us to generate any particular value. Now if we just
33:52:43
want to generate zero coins uh how many number of coins do we need? Well answer
33:52:49
is pretty trivial actually. Uh we simply need zero coins. Uh and this becomes our
33:52:56
base case. So now let's take let's say for the second value amount of one that
33:53:02
if we want to generate value number one how many distinct coins we need. So whatever value is we will check first of
33:53:10
all in our coins for all the values uh that are given in the coin to see if we
33:53:15
can directly use if the given coin is lesser than the value we are trying to achieve can we use that coin. So since
33:53:23
the value is one we can clearly see over here that this one if we just use one
33:53:29
coin we would be able to generate this value one. So the answer in this scenario becomes pretty simple that if
33:53:37
we just use one coin we would be able to generate this value. And notice that for
33:53:43
value number one we cannot use any of these three coins because they are all greater than our value one. So there is
33:53:49
no point in using them. Now let's repeat the process for amount
33:53:56
two. So for amount two if we want to generate the value to how
33:54:02
many minimum number of coins we need. So first of all let's check with the first
33:54:07
value. Okay. So coin is actually less than two. So we can use this coin. We will use this coin. So if we use that
33:54:13
coin basically we have already used one coin so far and
33:54:20
we since we use coin number one and we want to achieve value two. We can see that now the value we are trying to
33:54:27
generate is actually 2 minus one. So again value number one. Now we want to
33:54:33
generate value number one and if we we can do two either two things either we
33:54:40
can go back to all these coins again we try to generate that value or notice
33:54:46
this beautiful thing over here that we have already calculated that if we want
33:54:52
to generate amount one how many coins we are going to need. So why are we being
33:54:58
so picky and why are we doing all this extra work and why are we making our lives miserable, our CPU's life
33:55:03
miserable by doing all these additional calculations, why can't we just store this somewhere and if we have stored it
33:55:11
we can simply use it uh over here. So in this case we can say that we have
33:55:18
already used one coin in order for us to generate this one. And now once we have generated this one, we know that the
33:55:25
amount the number of coins that are needed to create value one is already computed. So we will do 1 +
33:55:34
amount to generate one coin. And this would be the answer if we want to generate two
33:55:40
the value two from the given coins. And this would become 1 + 1 so two. And this
33:55:47
would be our direct answer. And these are the minimum number of coins that we can use to generate value number two.
33:55:53
The reason I'm emphasizing so much on this is because this exactly is the core
33:55:59
concept of dynamic programming and we have just hit a very big hammer to its head. Basically we have said that hey
33:56:06
I'm going to take this dynamic programming all the way. I'm going to chew it all up so it becomes a second
33:56:12
nature to me. And now let's continue with our example. This is going to be a really long video but and I hope that I
33:56:19
recommend that if you just understood at any point I would just suggest you to go
33:56:25
ahead and uh start skipping over. So now
33:56:30
the value for amount two is actually two. Now let's calculate for amount three. The if we look at for amount
33:56:38
three we have now we have two options either first of all we can start
33:56:45
either first of all we can start with this value one we'll take value one then again the remaining value would be two
33:56:51
and we have already calculated that what is the amount that is remaining for value number two over here. So if we
33:56:58
let's take that approach just for the sake of understanding. So first of all we use coin number one. So we use coin
33:57:05
number one and plus the amount that is remaining is actually 3 minus 2. So we still have amount two that needs to be
33:57:12
computed in order for us to achieve this value three. So we can say that for this one the way we can do it is one coin
33:57:20
that we already used plus whatever the amount two we that we need to use and
33:57:26
notice amount two has already been computed over here. So we can say that 1 + uh 2 equals to 3. So if we choose one
33:57:35
of these coins and we try to achieve the value number three initially we would be
33:57:41
able to find our answer uh by using minimum of three tokens. Now again we
33:57:47
notice that now since we have computed this coin we notice that three value
33:57:53
number three is actually less than or equal to this given coin three and we
33:57:58
can use it to our advantage. So now we know that we want to achieve value number three over here. If we just use
33:58:04
this one coin, we would be able to achieve this amount number three. And current minimum amount that we have
33:58:10
calculated that is that we need minimum three coins in order for us to achieve value number three. So why are we using
33:58:17
three coins? Because our aim is to use the minimum number of values. So we can simply just say that if we just use one
33:58:24
single coin that is of denomination three, we would be able to calculate the
33:58:29
result as three for this amount three
33:58:35
and we won't be able to do anything with these two because they are already greater than three. So we can't make
33:58:40
three with those denominations. Now
33:58:46
let's move forward with our uh with the next value amount of four.
33:58:55
And if we generate the amount four how how many number of coins we need. So basically if we just take this first
33:59:02
coin we know that we have already used one coin and plus we have the value
33:59:08
remaining as uh amount three amount three is already
33:59:15
computed. We are using the best knowledge of computer processing we can
33:59:21
and based on that we can we can simply determine that. Oh and by the way this
33:59:27
would be one not three my mistake. So we can just simply say that if you want to
33:59:33
generate amount four we can do 1 plus amount three is already one. So we can use two and this would be the minimum
33:59:38
solution that even if we use the first coin as three we would use second coin as one and still the we will get the
33:59:44
same answer. So I'm not going to do whole computation but you get the idea.
33:59:51
So for amount four, we can say that uh two
33:59:57
are the minimum number of coins we need in order for us to generate amount four. If we want to do amount five,
34:00:04
how many coins we need? And the answer is pretty simple. We already have this five present over here. So we can just
34:00:09
simply write one. And uh notice again notice that we are going to check all
34:00:15
the coins uh and when we get to five we will be able to say that this is this is the minimum number of coins we can use.
34:00:21
Uh next is amount of six. If you want to generate amount of six again the answer
34:00:26
is one because we are already given a six over here and we are going to check through all the coins that are lesser
34:00:32
less in the value of whatever the amount that we are trying to calculate. Now let's calculate for amount of seven. If
34:00:40
we are calculating for amount of seven and if we check for the first coin uh the first coin is actually zero. So
34:00:46
basically we can just simply say that uh the first coin is the first coin is
34:00:52
actually one. So basically we can just simply say that we now we need we have already calculated the one coin plus now
34:01:01
we need to calculate the amount six because 7 - 1 is equal to 6 and we have
34:01:07
we already have the result for amount six. So we can just simply write that we need uh at least two coins in order for
34:01:15
us to generate the value number seven. And now let's try to calculate our output that we are want we are we have
34:01:21
already given that we need to calculate uh the eight. So if we want to calculate
34:01:27
amount 8 and based on this table it becomes pretty simple initially. So
34:01:32
first of all we will calculate this with value one. So basically we would be doing the calculation something like one
34:01:38
coin that we have already used plus amount of seven and we know that amount of 7 from our previous computation is
34:01:46
actually value number two. So we will do 1 + 2 = to 3 for this amount 8 that we
34:01:54
are trying to calculate. But uh can we do something better? And remember that
34:01:59
we are going to check all the coins. So because we are going to check all the coins when we get to coin number three
34:02:05
our solution would be that we have used one coin and that is co the coin uh
34:02:11
value is three and because we have used three now we need to generate the amount 8 minus 3 equals to 5. So we can say
34:02:19
that we used one coin to generate the value three and now we need to generate value five in order for us to achieve
34:02:25
this amount equals to 8. So if we do 1 + amount of five, what is the answer? And
34:02:33
the amount of five is already calculated over here as one. So we'll just simply
34:02:38
use that value and we'll do 1 + 1 equals to two. And we will carry on with our
34:02:44
computation with this value. Fine uh value five. Again we will find the answer two uh because we'll do 5 + 3.
34:02:50
And when we get to value number six, we will again find the answer to generate the amount eight as three because we'll
34:02:57
do like uh six plus amount of two.
34:03:03
So uh the minimum number of coins that we can find in order for us to generate
34:03:08
value number eight is actually two and we can simply return uh this value two. Now notice that we
34:03:16
also have to take care of the scenario where we cannot create the amount based on the given coins and if we cannot
34:03:22
create the amount uh at the end of our computation the value for amount would
34:03:29
amount of any given let's say 8 that we cannot compute in this case would
34:03:35
actually be uh the value 8 + 1 so equals to 9
34:03:41
because notice that at the beginning of our array Okay, this is how we initialize the values to and if after
34:03:50
all the computation we found that the value of amount is actually the original by default value that we set which is
34:03:56
amount + one. If that is the case we know that we are not able to generate this value and we are not able to make
34:04:01
any impact with our solution because the coins cannot generate this value. We will simply return minus one and this
34:04:09
solution would work perfectly fine. This is a really beautiful solution and if you go through with this approach in
34:04:14
your interview you are going to just be very impressive candidate and all the fang companies would want to hire you.
34:04:20
So what let's calculate the time and space complexity. So time complexity for this one would be uh actually big of n *
34:04:29
m. Now why n * n because we are running the loop to calculate the value n and n
34:04:35
is actually the value of this amount of whatever is given. So we are l we are
34:04:41
going through a loop n times and m are the number of coins
34:04:51
uh because notice that over here for every single element we will have to use the we will have to go through all the
34:04:57
coins in in order to generate the value. So the time complexity would be bigo of
34:05:02
n * m and the space complexity would be bigo of n because we are
34:05:09
creating an additional data structure array to store all these values and the values we are storing up to is actually
34:05:15
uh the amount whatever amount we are given. So we can say that the space complexity would be big of
34:05:25
okay. So let's create an array uh amount
34:05:31
and its size would be amount + one. We fill out all the values inside the
34:05:38
amount as
34:05:43
amount + one. This would help us determine that
34:05:49
whether uh if we cannot create the value we we need to return minus one or not.
34:05:55
And now uh we will set up the initial value for amount of uh zero would be
34:06:01
zero. Now let's create our loop. So
34:06:08
we will start with i equals to 1 because we have already calculated the value for amount zero. And while I is less than or
34:06:16
equal to amount.
34:06:24
Uh now notice that for every single value of I we need to calculate for all
34:06:29
the values of coins. So we will we will have another loop uh
34:06:36
that would iterate over coins.
34:06:43
And first of all we will check that if our present I is actually greater than or equal to whatever value of coin that
34:06:51
we are uh comparing it with. So if this is true then only we will check that
34:06:57
whether what is the amount uh for any given j uh sorry any given i. So we'll
34:07:05
do a minimum value of either the value itself. So whatever
34:07:12
value we already have or we will take one coin of any J
34:07:21
and we will do an amount of I minus J
34:07:32
and yep this is the main logic uh because in this logic we are calculating
34:07:38
uh all the amounts and we are using it uh further down the road as well. So
34:07:44
after this iteration we just need to check that if uh for any given amount so
34:07:52
amount of amount if that is um less than
34:08:01
the value amount + one which means that we have been able to generate this
34:08:07
amount. So in that case we would return whatever the value we found.
34:08:16
Else we can simply return minus one.
34:08:25
Let's try to run this code. We made a silly mistake
34:08:36
again. Oh, we need to check with coins of J.
34:08:49
Yeah, looks like our code works. Let's try to submit this.
34:08:56
And yeah, our submission is actually pretty efficient compared to other uh others who have submitted. So, I hope
34:09:05
you like this video. It took me a lot of time to make it and I know it was a really long video but it was believe me
34:09:11
it's equally informative. Once you master dynamic programming you are
34:09:16
almost guaranteed that you at least have a foot in the door for fang. And uh yeah
34:09:22
we are not going to stop till we clear fang. See you.
34:09:34
Hello friends. So we are still not employed by fang company. So let's not stop lead coding till we get there. Today we are going to do a very
34:09:39
important lead code problem. Decode base. And uh this problem has been asked in bunch of different fang companies
34:09:45
like Amazon, Google, Facebook, uh Microsoft, Uber, Lyft, Apple. So I
34:09:52
highly recommend that you focus full attention to this problem. Uh this is the breakdown that we are going to do
34:09:58
for this problem. We are simply going to understand the problem. First we are going to see a brute force solution.
34:10:03
Based on the brute force solution, we are going to see that how can we create an optimal solution and eventually we
34:10:09
will write the Java code for that. And uh this is a late code medium problem
34:10:15
and we are given a note that uh basically a message can containing
34:10:20
letters can be encoded into numbers using the following method. So a is 1, b is 2 and up until that if we keep doing
34:10:28
that uh z is actually 26 and uh we are given a string of uh s that contains
34:10:36
digits and we need to return the number of different ways we can decode it. So let's understand this with an example.
34:10:42
Suppose our given input s is equal to 12. Uh we can decode this in uh two
34:10:48
ways. So one way to decode this would be to consider 1 and two as separate elements and 12 by itself as a single
34:10:56
digit. So this uh the value for 1 and two would become a and b using this
34:11:02
logic and uh the value of 12 would become the letter l. So we don't need to
34:11:08
return these values. We don't care about them. The thing is we need to return that how many different ways we are uh
34:11:14
decoding this uh given input string. And in this case the answer would be two. Let's take another example. So suppose
34:11:21
our given input S is equal to 26. How many times how many different ways we can decode this one? So one way to
34:11:28
decode this one is uh 2 and uh 26. So that's one way. Second way to decode
34:11:34
this one is two or two and six. So that is second way. And the third way to
34:11:42
decode this one 22 and six. And uh if we
34:11:47
check out the values. So this would becomes B uh Z. This would becomes B B F
34:11:55
and this would become V F. So over here we can see that there
34:12:02
are three ways we are uh decoding this given string. So in the answer we will return the value as three. Now there is
34:12:10
let's consider one more case. Uh suppose the value zero. 0 would be a special case and there could be multiple
34:12:16
possibilities where zero can appear. So suppose our given input S is something like 0 1.
34:12:22
So in this case we won't be decoded in any manner because uh remember that our
34:12:28
range starts from this value number one up until 26. So 0 is not part of the
34:12:34
range. So we cannot begin our uh string with value zero at the beginning. So
34:12:40
this won't work. Uh second possibility that zero could be somewhere in the middle. So suppose the our given input S
34:12:48
is equal to 1 0 1 something like this. So in this case we cannot decode this in
34:12:55
1 and 0 1. We can't do this. Why? Because we can't decode this 01. Because
34:13:01
remember that in this scenario if zero comes at the beginning we can't decode it. Uh the way we can decode this is we
34:13:08
can consider this as 10 and this as one. That value of 0 can appear at the end.
34:13:14
So our input string s can be something like uh 2 0 0. So in this case we can
34:13:21
decode this value to 0 but we can't decode the zero. So we won't be able to return anything or our value s can be 5
34:13:29
2 0. So in this case we can decode this. We can decode this value five and we can decode this value 2 0 because 2 0 is
34:13:36
again between 1 to 26. Uh but if we are given something s is equal to like 5 7 0
34:13:44
we can't decode this because we can decode this five but we can't decode 7 0
34:13:49
because 70 is not part of uh this 1 to 26 range. So when value 0 comes in it
34:13:56
becomes a little bit tricky and we have to just take care of it. For brute force approach, let's take a
34:14:03
custom example. Suppose our given S is equal to 2 1 2 3 and uh we need to see that how many different ways we can uh
34:14:10
decode this one. So brute force approach is pretty simple. We just take all the possibilities uh starting from the first
34:14:17
value and keep moving and keep building our solution and when we reach at the end at any given path we consider it as
34:14:23
a one way to decode it. So initially we can decode this as two and rem whatever
34:14:29
the remaining value 1 2 3 we can decode this further into two 1 and whatever
34:14:37
value remaining again same thing 2 1 2 and uh this three and uh in the in
34:14:47
the end we can decode this as 2 1 2 3. So this would be one way we would
34:14:56
be able to decode this. So where if we treat all the values as separate entities.
34:15:02
Now let's see let's go back and see that can we can we have more possibilities.
34:15:07
So over here we cannot have any more possibilities because this two one and two are already being decoded and this
34:15:14
three we only have one possibility to decode it by itself. So we don't have any any possibility over here.
34:15:21
So we go back uh further up. Do we have any possibility over here? So yes over
34:15:26
here we still have possibility that we can decode this two and one the same way
34:15:32
we have decoded over here. But this 23 we can decode it as a single value. So
34:15:38
of course we reach at the end of the loop. So this is one more possibility on how we can decode it. Now let's go back.
34:15:46
So for this value 123 uh of course we have we still have more possibilities
34:15:51
because over here we are considering this value as two and one separately. So
34:15:57
over here we will consider this as two as already being decoded and rather than
34:16:02
considering this as one as separate character we can also consider is it as one two and then we can decode three. So
34:16:10
this can also be another way. So we'll just mark it. Okay. Now we have
34:16:17
exhausted all the possibilities over here. Uh considering this value if we
34:16:23
start from this value number two. So we come back at our uh main point and let's
34:16:28
see that what are the more possibilities we can have over here. So we can do
34:16:34
rather than choosing two we can choose 2 one and whatever the remaining stream. So remaining is 23. Okay. Now let's see
34:16:41
that how many different possibilities we can have over here. So we can have two possibilities now. We can do like 21 2
34:16:51
and 3. So that is one option or we can do 21 and 23. So that is second option
34:16:59
and uh yeah both would be a separate ways and apart from these we cannot make
34:17:06
any other possibilities. So essentially we are uh we can say that there are five
34:17:11
different ways to uh decode this 213 string and uh those five ways are um
34:17:18
mentioned over here. Now uh
34:17:23
what is the problem with this brute force approach? Well the problem with brute force approach is that actually we are doing lot of repetative work. Uh how
34:17:30
we are doing repetitive work? If you notice over here that we know that we
34:17:35
need to calculate that for this 23 how many different ways we can compute this one. But this 23 we have already
34:17:42
computed it over here. So we since we have already computed over here it is
34:17:47
not very fruitful to compute the same thing twice and uh in brute force we are
34:17:52
not doing it. So that is why our uh path will keep on go growing and growing
34:17:59
until we reach to our uh all the possibilities which means that we are
34:18:04
actually doing exponential work for this brute force approach. Uh so of course the big the time complexity would be big
34:18:11
go of 2 to the^ n which is really bad and uh we should avoid it in all cases
34:18:23
and actually it can be avoided pretty simply if we just use memoization. If we
34:18:28
just create an additional data structure something like an array or something where we store the value of calculations
34:18:34
that we have already done and if we at any point come back to the same calculation that we have we have already
34:18:41
computed. We can simply return that value. So we can use something like an array or hashmap. I think hashmap would
34:18:48
be more efficient in this case because we can we are able to look up things in constant time. And if we only apply that
34:18:55
we can actually implement this solution the this brute force solution in very
34:19:00
effective manner. we can actually use recursion because uh remember at every single moment we are repeating a sub
34:19:08
problem. So we are repeating a sub problem and we are computing that. So if
34:19:13
we just use memorization with recursion. So
34:19:19
for for this approach we can actually achieve the answer in time complexity of
34:19:24
bigo of n rather than this 2 to 2 to the^ n and that would be really efficient.
34:19:33
Okay, before I go into the optimal solution, I want to show you a few observations. Suppose our given input S is equal to 7.
34:19:41
So how many different ways we can decode it? Of course, only one way we can just use seven. Suppose our input is 77. We
34:19:47
can still only decode it one way uh using like 77 and that would be the only way we would be able to decode it. Even
34:19:55
if our value is 777 777 whatever the value we have all of these
34:20:02
can only be decoded just one way because all of these values they are forming a
34:20:09
value where we can only use individual characters. Now what is the scenario where we can use the characters that are
34:20:16
not individual and we can uh collectively use the pair of elements.
34:20:21
Okay. Now let's take one more example. S is equal to 2 1 2 3 and now let's try to
34:20:28
see that how many different ways we can decode this one. This is the same one we have used in our brute force approach. So we know that there are five different
34:20:34
ways we can decode this one. The thing is we are going to do things a little bit differently over here. We are going to decode these all of these values. So
34:20:42
first we'll start with value number two. How many different ways to decode this one? Only one way and that way is
34:20:49
two. Now let's consider the second value 21.
34:20:54
How many different ways to decode this one? Well, of course, two values or two different ways and those ways are 2 1.
34:21:03
So that is one way and second one is 21 by itself. And uh
34:21:10
let's take the third value 2 1 2. So there are actually three different ways
34:21:16
to decode this one. Let's consider the next value is 2 1 2
34:21:23
3. So we know that for this one there are actually five different ways to decode
34:21:29
this and the five ways are
34:21:34
okay you must be thinking that why am I writing all these letters because the
34:21:39
thing is there is actually a very important uh relationship that exist whenever we find out uh whenever we add
34:21:46
a new value to our to our calculation and if that value that is being added if
34:21:53
the previous value of that with that particular value if that falls between this 10 to 26 actually something
34:22:01
interesting happens. So notice over here that this uh 21 came in
34:22:10
okay we are we are checking for this value number 21. Now the thing is just
34:22:15
for a second imagine if this value was actually 27. So how many different
34:22:20
different ways would we be able to decode this one? Well, only one different way and that one different way
34:22:26
would be two and seven. So, treating both values as separate values. Uh, same
34:22:31
goes for 28, 29 and any value above. But the thing is because this value falls
34:22:38
between this 10 to 26 portion, we are able to do something interesting. So
34:22:43
notice that whatever value we append over here, there is there will always be
34:22:49
one way to decode it. I'm not talking about the value zero. Forget about zero. Apart from zero, if there was any other
34:22:56
value, the way to decode it would be to whatever the way we have been decoding
34:23:01
the previous value. If we just add that value, then that would be the way to
34:23:07
decode it which is over here. That two and one we are already decoding it with
34:23:13
whatever value we were using we were decoding before and we were using that way. But the thing is over here this 21
34:23:21
by itself falls under this 10 to 26 which means it is a letter by itself. So
34:23:26
we are able to add it to our decode list and that is why we have two over here. Okay. But now the interesting part comes
34:23:34
in. Okay. Now over here we are adding one more two and this two falls between
34:23:40
the value z uh 10 to 26 because the appending value becomes 12. So this 12
34:23:46
falls between this 10 to 26. Now let's see that how many different ways we are creating the pairs. Actually 2 1 and 2.
34:23:54
This is same from whatever the pair we had before one just one iteration
34:23:59
before. Okay. Now this 2 1 we already have had a 2 one over here and we are
34:24:04
just appending this value two over here. So that is also okay because we can append it right. So whatever the ways we
34:24:12
were we were decoding before we are still using those ways. But the thing is over here something interesting happens
34:24:18
because this one two by itself is a way to decode. We are actually able to
34:24:25
create this 212 pair which we were not able to generate over here. We are not able I mean we are using this two over
34:24:32
here but the thing is we are using it for 21 but we can't do anything further than that. We are already also using
34:24:39
this 212 over here. And how can we say that we are using this 212 over here is
34:24:46
because this value is basically 12 uh falls are between 10 to 16. But the thing is this two actually comes from
34:24:54
the first value this one. And uh
34:25:00
why? Because at any given moment we find out that there exist a pair with the new
34:25:08
value being added and that comes between this 10 to 16. We can actually do sum of
34:25:14
previous two values that we have calculated so far and the sum of these two would actually give us the number of
34:25:20
different ways we can actually decode this one. If you still don't believe me, let me show you with an with another
34:25:26
example. Let me clean this up a bit.
34:25:33
Now over here we are seeing that five distinct pairs are being made and we are adding the value three over here and we
34:25:40
know that this uh pair 23 exist between this 10 to 26. So that is all okay
34:25:46
right? We we know all of these stuff. Now let's see that how many different ways we are generating the pair. So one
34:25:53
way is 212 and we are just appending three. This would be the case even if
34:25:58
the value was 2129. If the value was 2129, we would still be able to use this
34:26:03
way because a apart from this three that there would be a nine over here. But that's not the case right now. But the
34:26:10
thing is we we would still be do do it. And if you look at look over here, this is the same path we were taking and we
34:26:17
are just adding one more node. So no impact on the number of results. Second
34:26:22
pair we are making is actually 212 and we are appending three over here. Again
34:26:27
that is the case over here that we already had a 212 and we can append three over here. So that that gets uh
34:26:35
taken out over here. If we had the 21 29 we would be appending 9 over here. So
34:26:40
that still remains common. Okay there are no issues with that. Now next pair over here is 2 and 12. So we also have a
34:26:49
2 and 12 pair and we are adding a three over here. Which means that even if we had this nine, we would still be adding
34:26:55
nine and that would be it. We we we don't care about it. But the thing is if
34:27:01
we had this nine, we won't be able to generate these two pairs because notice in these two pairs, we are actually
34:27:08
creating an additional value by the value that has added over here. And if
34:27:15
we if this value was not between this 10 to 26, this value would not been able to
34:27:22
be generated. Okay. Now the question comes that
34:27:28
we have already exhausted all the possibilities over here.
34:27:33
So where does these two additional values comes from? Well, actually if we look above over here, this one is
34:27:40
actually 21, right? So we are also using 21 and we are creating a new decode node
34:27:48
23 and we are appending appending it over here. Also notice over here that
34:27:53
this one is 21 and this one is 21. So we are appending a node over here uh 23
34:28:00
which means that at any given location if we want to see that how many times we
34:28:06
can decode it we if we know the information of previous two elements and if we do sum of those uh we can actually
34:28:13
generate it. So that's why uh the value for this uh 21 this can be decoded two
34:28:20
times this value 212 this can be decoded three times. So for the value 2 1 2 3
34:28:28
actually this 23 falls between 10 to 26. That is okay that is perfect. If that
34:28:34
that is the case we simply do an addition and if we do an addition and we just uh find whatever result we have
34:28:40
calculated and we can simply return this. This is a very effective solution.
34:28:46
Now what could be the other case? Well the other case could be that the new value we are adding that does not fall
34:28:53
between this 10 to 26. So suppose over here the new value we are adding suppose
34:28:59
the new value is 218 something like this. So after adding this new value uh
34:29:04
this becomes 28 it does not fall between this 10 to 26 because it does not fall between this 10 to 26. Actually we don't
34:29:11
need to do addition over here. We simply need to whatever the route we can make
34:29:17
before this element. that would be the only possibility we would be able to decode this one as well because that I
34:29:24
just showed you over here that over here I was adding a nine and because I was adding a nine I was only able to uh make
34:29:33
the new decode paths for these three elements. I won't be able to generate these two values and this becomes our
34:29:40
recurs recurrence relationship and this actually becomes our dynamic programming
34:29:46
solution. Now let's try to solve this dynamic programming programmatically. We know
34:29:52
that we need we care about the two previous elements. So suppose our given input is like 2 1 2 3 we initial and we
34:30:01
initialize two values before that as 1 one and say we have these two as 1 one.
34:30:07
Now we check at any given location that whether the value we have does it fall
34:30:14
does this value with its previous value does it fall between this 10 to 26. Okay
34:30:21
in this case this two does not fall between 10 to 26. If it does not fall between 2 to 26 we just need to take
34:30:28
whatever we had from the previous element. So previous element over here we had one. So we'll we'll just take
34:30:34
one. Okay. Now we have this one. So again we check with its previous element
34:30:39
that whether the value falls between this 10 to 26. The value becomes 21. It falls between this uh 10 to 26. So we do
34:30:48
whatever the previous two elements were we do sum of it. So the previous one element is 1 and the previous second
34:30:56
element this one is also one. So we do 1 + so we do 1 + 1. So we can put two over
34:31:02
here. Now we have new element. This falls between this 10 to 26.
34:31:07
That's good. So we do sum of two previous elements. Sum of two previous elements is actually 2 + 1. So we can
34:31:14
put three over here. Now we have this three. Now we it creates the value 23.
34:31:19
Again falls between this. So we can do sum of 2 + 3 and that becomes five. And this five would be our result. So this
34:31:27
is a very important dynamic programming solutions. And uh at any given moment if
34:31:32
we find out that suppose over here we have an value 8. Now this 38 does not fall between this 10 to 26. So it
34:31:39
becomes simple that for this pair the number of ways we can decode this will still be five because we'll just take
34:31:45
whatever value we have calculated over here. This solution works perfectly fine. And
34:31:51
the time complexity for this case would be big of n because we only need to do one iteration across all the strings.
34:31:58
And uh the space complexity would in this case would actually be big of one. We would be able to complete this in
34:32:03
constant space and time because remember that at any given location we only need to keep track of just two elements. We
34:32:09
don't need to cap keep track of this whole entire array. we just need two starting elements and uh we would keep
34:32:17
on iterating them over uh different values. So this is a very good solution
34:32:22
and uh okay first of all we will check that
34:32:28
whether the first element is uh zero or not.
34:32:34
If this is the case we can simply return zero.
34:32:40
Okay. So we will create two parameters uh one and two and we will initialize both to value one.
34:32:48
Let's run a for loop. We'll start the loop from first position
34:32:54
and we will go up until the length of the given string.
34:33:01
We we are running it from i equal to 1 because we already check for the zeroth position.
34:33:06
First of all, we create a value current to keep track of the current element. And now we check that if the current u
34:33:15
if the new character that we are trying to add if that is not equal to zero,
34:33:23
we can assign the one the value of one to current.
34:33:31
Now we also need to check that after adding the value at e position are we
34:33:36
getting the twodigit value between 10 to 26. So first of all let's create a new variable uh called uh value and we will
34:33:46
try to calculate the twodigit value.
34:33:52
We check the condition. So if value
34:33:58
is greater than or equal to 10 and
34:34:06
value is less than or equal to 26 which means
34:34:12
we need to update the current value is
34:34:17
current plus whatever the value of two we had because remember the value at current we
34:34:23
we are already adding it as one. Now we need to update the values of one and two. So
34:34:29
two would become whatever the value of one we had and one would become whatever the value of current we had.
34:34:37
And uh yeah I think this this would be our solution. So at the end of the
34:34:43
solution we need to return the value of whatever the current value we had. But
34:34:48
since we are initializing current inside, we'll just return the value as one.
34:34:55
And uh let's try to run the code. Oh,
34:35:03
we can initialize the current as zero. Let's try to run the code.
34:35:08
Okay, looks like our solution is working. Let's try to submit the code.
34:35:15
Okay, our solution works pretty fast and pretty efficiently. So, I'll be posting
34:35:20
the solution in the comments. You can check it out from there.
34:35:32
Today we are going to do maximum product subarray. This is a very popular problem on lead code. And if you see some of the
34:35:37
companies where I want to get a job who have already asked this question, there are companies like Amazon, LinkedIn, Microsoft, Google, Apple, Bloomberg,
34:35:43
Facebook and Uber. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
34:35:50
Okay, so this is a lead code medium problem and as mentioned a very well-liked problem on lead code. Basically, we are given an integer array
34:35:57
called nums and we need to find a continuous non-MPT subarray that has the largest product and we need to return
34:36:04
the product. uh we are also given the definition that what a subarray is that is basically a continuous sequence
34:36:09
inside the any given array and let's try to understand this problem with the with an example so I have broadened this
34:36:15
example over here and basically we are trying to find the maximum product subarray so a subarray that contains the
34:36:21
maximum product in this case this is a negative value and that changes the dynamic equation so in this case the
34:36:27
product of these two elements that is a subarray is actually going to be six and all the other subarrays they are always
34:36:34
going to have lesser values than six. So in this case as the answer we need to return six that that is the maximum
34:36:40
product subarray we can make for this given input array and this is what the problem is asking us to do. So first
34:36:46
let's see that what is going to be the brute force way to solve this problem. Well the brute force way to solve this
34:36:52
problem is that we are asked to find the maximum product subarray right. So if we are asked to find something of a
34:36:59
subarray, why don't we check every single subarray see that what is the product we can make and find the maximum
34:37:05
amongst that. So like do the baby steps. So what we are going to do is we are going to keep on iterating over every
34:37:12
single subarray that we can make. Uh we are going to see that we are going to have a variable called answer and uh in
34:37:19
the answer we are only going to store the maximum value we have found so far. And then we will keep on repeating the
34:37:25
same process for all the remaining subarrays. And eventually we would find a pair that contains the maximum product
34:37:32
subarray. And in this case the answer is actually going to be this 6 * 7 that is 42. And we will have 42 populated as the
34:37:40
answer eventually. So the brute force way is a very trivial way but it leads
34:37:46
to the correct solution. So if you are only looking for solution you will get it using brute force. But what are the
34:37:51
issues with this one? Well, the issues clearly we can see over here that we will have to iterate over every single
34:37:58
subarray that is there and that would lead us to have a time complexity of
34:38:03
bigo of n². So which is very bad because for every single element we will have to
34:38:10
iterate over every other elements and then keep on repeating the same process. So the idea is to see that can we find
34:38:16
something of a better time complexity. We can actually achieve that using the
34:38:22
most important concept inside our computer programming and that is called dynamic programming. Using the dynamic
34:38:28
pro programming we are basically going to have two pointers to store some critical important results and that is
34:38:35
going to lead us to find the maximum product subarray. So first let's understand one thing regarding what is
34:38:41
being asked. We are trying to find the product. Now we know that for the product suppose if all the integers are
34:38:47
just positive inteious then basically it is the product of all the inteious that we need to return right but the thing is
34:38:53
that is not always the case. We could encounter negative inteious and the negative inteious leads to very uh
34:39:00
interesting results. The interesting results are that first of all we suppose in this case uh these three values if we
34:39:07
do product of them okay the product of these two is 6 and the 6 * -3 leads us
34:39:12
to -8 to be the product over here right the thing is now this value seems very
34:39:18
low value because of the negative value but imagine that over here rather than this four being positive if we had a -4
34:39:26
then that is actually going to lead us to have a very beautiful results that if we do -8 18 * -4 the answer is going to
34:39:33
be + 72 and that is going to be the maximum product subarray. So you see
34:39:38
what I'm trying to say the moment we encountered a negative value immediately we found it to have the minimum value
34:39:45
but that negative value lead us to have some better consequential results in the
34:39:50
future. So we don't know that whether we whenever we encounter a negative value we don't know whether we should keep it
34:39:56
or not. So that is a tricky part. That is why we are going to use dynamic programming and we are actually going to
34:40:03
use two pointers. And these two pointers are going to be that at any given position we are at inside our array we
34:40:10
are going to see that up until this point what is the minimum value we have been able to achieve and what is the
34:40:16
maximum value we have been able to achieve or basically what I'm trying to say is what is the minimum product we
34:40:21
have been able to achieve and what is the maximum product we have been able to achieve and every single value we could
34:40:28
have three possibilities so let me clean this up a bit at every single value we
34:40:33
are at there could be three possibilities. Either this value could be part of a subarray that leads us to
34:40:40
have the maximum product or it could have been a part of a subarray that leads us to have the least value up
34:40:46
until this point or this could be the start of a new subarray that leads us to
34:40:52
have a maximum product in the future. The idea is at any given position we are
34:40:57
going to check three things. And the three things we are going to check is that up until this point whatever the
34:41:03
minimum value we had which is which we have stored so far we are going to multiply this value with this minimum
34:41:09
value we are also going to multiply this value with whatever the maximum value we
34:41:14
have able we have been able to store so far and we are also going to compare this value by itself. So we have
34:41:20
basically three values at any given position. The value with the previous minimum value, the value with the
34:41:26
previous maximum value and the value by itself. And for all of these three values, we are going to see that what is
34:41:32
the minimum value we are able to make, we will store that. What is the maximum value we we are able to make amongst
34:41:38
these three values? We will store that as well. And eventually we would reach to the end of our loop with the maximum
34:41:45
value we have been able to generate. And we will have a parameter called answer. and in the answer parameter whenever we
34:41:51
identify a better maximum value we would populate that. So this is the approach I'm suggesting. Now let me try to go
34:41:58
over an an example. Okay. So suppose this is the example we are have. And now let's try to use dynamic programming in
34:42:04
this case with two pointers. So we are going to create two pointers called min and max. And for every single value we
34:42:11
are going to compare it with three values that we are going to compare it with. And we are going to populate these
34:42:17
results. We are also going to have a variable called answer. We will update it based on the maximum value we have found so far. Okay. So first value is
34:42:23
five. So we for all the three values we only have five. We can't compare any with with anything. Okay. So minimum
34:42:30
value we have found so far is going to be five. Maximum is also going to be five. And that's it. Now this next value
34:42:35
is three. Okay. So now let's see that what are three values that we have to compare. So first value is three by itself. Next value is three * the
34:42:42
minimum value. So 3 * 5. Next value is 3 * maximum value. So again 3 * 5. So the three values we have is three, 15 and
34:42:49
15. Okay. So now the minimum value amongst these three is going to be three. So we are going to populate that
34:42:54
and the maximum value is going to be 15. So we are again going to populate that. The answer so far that the best we have
34:42:59
received is 15. So we are going to populate that. Okay. Now let's get rid of this one. Now again we are at the
34:43:05
next element that is one. So now the three values we have is 1. 1 * whatever the minimum value so that is three. So
34:43:11
the value is going to be three. And the 1 * the maximum value that is 15. Okay. Now amongst these three values the
34:43:17
minimum value we can able to make is going to be 1. Okay. So let's populate that and the maximum value is going to be 15. The answer is going to remain the
34:43:24
same. Now let's clean this up. Okay. Now things become interesting when we reach to this value 9 minus 2. Okay. Now the
34:43:30
three values we have is going to be -2 by itself. Then -2 * the minimum
34:43:35
previous minimum value. So previous minimum value in this case is 1. So -2 * 1 is going to be minus2. And the
34:43:41
previous maximum value. So previous maximum value in this case is 15. So -2 * 15 is going to be minus30. Okay. Now
34:43:48
these are the three values we have. And now we are going to see that what is the minimum and maximum value we are able to
34:43:53
generate. Right. So currently the minimum value we are able to generate is going to be minus 30. So we are going to
34:43:59
store that over here. Okay. And the maximum value we are able to generate in this case is going to be minus2. So we
34:44:05
are going to store that over here. Okay. Now we are good up until this point. Now this value is zero. So the three values
34:44:11
that we have to compare is going to be 0 0 * the minimum value. So that is again
34:44:16
going to be the 0 and 0 * maximum value that is again going to be the zero. So all three values are zero. So let's put
34:44:22
zeros over here. Now again we are at this value number five. So now the three
34:44:27
values that we have to compare is going to be -5 and then both of these are zero. So it's going to be 0 0 again. So
34:44:33
currently the maximum value we are able to generate is going to be the zero. So we are again going to populate the value
34:44:39
with zero. And the minimum value we are able to generate is ne5. So we are going to populate the value with ne5. Now the
34:44:44
next value is 8. Okay. So now the three values we have to compare is 8. 8 * -5 is going to be -40. And 8 * uh the 0 is
34:44:52
going to be zero. Okay. Now uh the three values that we have let's compare them
34:44:58
and let's find the minimum value. So minimum value in this case is going to be -40. So we are going to put it over
34:45:03
here. The maximum value we are going to have is 8. So let's populate that over here. Okay. Now we are at this value
34:45:09
number minus3. So with this minus3 we again we have three options. So minus3
34:45:14
and then -3 * this -40 that leads us to positive 120 and -3 * 8 that leads us to
34:45:20
-4. Okay. So now in this case the minimum value we have so far is going to be -4 which is this one. And the maximum
34:45:29
value we are going to have is going to be 120. And this 120 is greater than this value number 15. So we are also
34:45:35
going to update that in our answer. And now we have reached to the end of our array. So end of our dynamic programming
34:45:42
journey. So we'll stop here. And whatever value we have found in the answer, we are going to return this as the answer. So in this case, answer is
34:45:49
120. That is the correct answer. If we see and if we compare this to our brute force, well essentially because we are
34:45:56
using the beautiful concept of dynamic programming, we are completely everything in just one single iteration.
34:46:01
And all we are doing is just storing couple of variables. uh to store the previously calculated results and
34:46:07
comparing different values and that leads us to have the correct answer and find the maximum product subarray in a
34:46:12
single iteration which is wonderful. If we see time complexity in this case the time complexity is is actually going to
34:46:18
be big of n and the space complexity is actually going to be bigo of constant
34:46:23
space complexity because apart from storing couple of variables we are not storing any other data. So this is a
34:46:29
very good time and space complexity to have compared to a brute force approach that had the time complexity of big of
34:46:34
n² which was very bad.
34:46:40
So first let's take care of some match cases that if the given number is empty we can simply return zero. So now we
34:46:46
will initialize a min variable a max variable and a result variable. Okay. So now let's run a for loop to iterate over
34:46:53
our given nums array. Let's initialize a variable called current to keep track of the current variable we are at. Okay.
34:46:59
Now we will have to calculate max and min value. So first let's calculate max value. So this takes care care of
34:47:05
comparing three values for our max variable. And we are using math domax function two times because that is the
34:47:11
way to do it. I think in Python you can do it just without using like two math domax functions. Now let's calculate our
34:47:18
min value as well. The thing is for our min value we will also have to use the max value. But since previously we have
34:47:24
already calculated our max value, it makes no sense for us to use that over here. So what I'm going to do is I'm
34:47:30
going to create a temporary variable and this temporary variable I'm going to calculate the max value. Then for the
34:47:36
calculation of min value basically I'm going to use the previous u max
34:47:43
variable. Now because this is the temporary variable we will assign this value to max. We will also have to keep
34:47:49
on updating our result variable as well. That's it. Uh, basically when the loop ends, we should have our answer
34:47:55
populated in the result variable. So, let's return that. Now, let's try to run this code.
34:48:00
Okay, seems like our solution is working as expected. Let's submit this code. And our code runs pretty efficiently
34:48:06
compared to a lot of other solutions. And I will be posting this solution in the comments. So, you can check it out from there.
34:48:21
Now the next problem we are solving is called longest increasing subsequence. This problem actually has two optimal
34:48:27
solutions. First optimal solution is a dynamic programming solution that can solve the problem in big of n square
34:48:34
time and which I'm explaining in the first part of this video. Now for the same problem there is an even better
34:48:40
solution which is very tough to understand and that is something that is using a patient sort algorithm. So the
34:48:48
thing is if you are only considering and trying to learn dynamic programming I think part one of the solution should be
34:48:53
fine. If you also wants to learn the optimal approach for the same problem you can also see the part two of the
34:48:59
same question. Uh so there are going to be two solutions for the same problem. And uh now let's start understanding the
34:49:06
problem statement. Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we
34:49:12
are going to do a very important lead code medium problem uh longest increasing subsequence and I have
34:49:17
decided to break this video in two parts. In the first part I'm going to discuss the uh brute force solution and
34:49:23
an accepted uh solution for this problem and in the second part I'm going to show the optimal solution. But the thing is
34:49:29
the optimal solution is really difficult to achieve and it's a little bit tricky to come up with. So let's understand the
34:49:35
problem statement. Basically we are given an array of numbers and we need to find the length
34:49:41
of longest strictly increasing uh subsequence. So uh subsequence means
34:49:48
that suppose we are given an input like this uh 1 2 4 5. So we can say that the
34:49:55
value 2 and five is actually a subsequence of this given initial problem. Let's try to understand that
34:50:01
what is the input given. So we are given over here
34:50:06
an 18 and this example and uh if we take
34:50:12
these numbers uh 2 3 7 and 101 uh this would be our longest increasing
34:50:19
subsequence. So if we get rid of this value five, this would be the longest subsequence we can make where all the
34:50:25
values are in increasing order and the length of all the values would be four, which is what we need to return as a
34:50:32
part of this uh output. So once we know the problem statement, let's see that
34:50:38
what could be the brute force approach.
34:50:45
So in the brute force approach, so in the brute force approach, we are simply going to take every single subsequence
34:50:51
that we can possibly make uh keep a parameter that tracks the length of any
34:50:56
subsequence and eventually at the end we would we should be able to find a subsequence with the maximum length. So
34:51:03
let's take a small example and see that how what are the possible subsequences we can make. So suppose our given input
34:51:10
is 5 3 and 8. I'm only taking three elements because I am I need to show
34:51:15
that why this approach is bad and what are the possible subsequences we can
34:51:21
make make out of this. So let's start making all the possible subsequences. Uh the possible subsequence would be five
34:51:27
53 58
34:51:33
38 8 and 5 38. These are the possible
34:51:41
subsequences we can make out of only the these given three problems. And if we
34:51:46
check the length of each of them and if we find out the property that which one is the which one is a strictly
34:51:52
increasing order we found that this is the strictly increasing order and the maximum length we can achieve is two. So
34:51:58
this solution works it works fine. The problem is that notice that we are only
34:52:03
given three elements over here and based on this three elements we were able to make almost seven subsequences.
34:52:09
Mathematically it's actually 2 to the power of 3 minus one and for any s any
34:52:15
single given n this is the number of subsequences we can make. So suppose we
34:52:21
are given n values in the given input. The number of subsequences we we would be able to make would be 2 to the^ of n
34:52:28
minus one. So if we calculate the time complexity we can just say that the time complexity is actually big go of 2 to
34:52:34
the^ of n which is extremely horrendous uh time complexity uh and this is
34:52:40
exponential. So even give with with enough numbers even NASA
34:52:47
won't be able to solve this one. So let's move on to the next approach
34:52:57
now. Now we want to find the better approach and we know that the way to do this is
34:53:02
to use dynamic programming. The thing is how can we identify that we need to find the solution using dynamic programming
34:53:10
also what dynamic programming solution are we going to use. So I'll be discussing both the things in uh next
34:53:16
portion and uh first of all let's take an example. We'll try to see how we are going to solve it. Then I'll show you
34:53:23
how we can determine that we are using the dynamic programming and after that we would be imple implying uh the result
34:53:31
and I would be showing you the coding example. Suppose our given input is
34:53:37
suppose this is the input given and we need to find the longest increasing substring. So just by looking at the
34:53:45
given example we can determine that the longest increasing sub substring actually exists between 7 8 16 and 27.
34:53:53
And now let's see that how can we come up with this solution. How do we
34:53:58
determine that this is dynamic programming. Suppose we are just given an example
34:54:04
like this. We are just given one value that let's say the value is seven. If we
34:54:09
are only given seven, what is the longest increasing substring we can make? Well, the answer is quite simple.
34:54:15
We can simply make just one substring uh of length one. So, this actually becomes
34:54:21
our base case that if we are only given one value, we are guaranteed to have at
34:54:28
least one substring that would be the longest increasing substring that we can
34:54:34
make. So now let's see that how can we use this logic.
34:54:40
Say that for all the given elements basically there exist one substring at least
34:54:49
that is the longest increasing substring. Let's just mark all the values as one.
34:54:58
We know that if we are only given the value 10, the longest increasing sub substring we can make would only be one.
34:55:05
But when it comes to the second value, now we have something to compare to.
34:55:10
Suppose the seven value if this was greater than 10 and we only had two
34:55:16
values. We can say that at the second position the longest increasing substring that we would be able to make
34:55:23
would actually be whatever we have made so far + one. So we would have been made
34:55:28
two. But over here that's not the case. And over here the value seven is
34:55:34
actually less than whatever uh we are given the value before that which means
34:55:40
that we the longest substring we have at the value seven would also be one. So
34:55:45
this would be true in this case. But now when we come to 8 we have two
34:55:51
possibilities. What are the total substrings we can make up until this point up until 8.
34:55:58
Okay. So for this value 8 what is what is the
34:56:03
one thing that we can determine? We can basically determine that there are three possibilities of the substrings we can
34:56:10
have and we can compute. One possibility is we could have a substring like 10 and
34:56:15
8. Second one is we have we could have substring 7 and 8. And third one is we
34:56:21
could have a substring 8 by itself. Uh in case if all the values before 8 are actually uh greater than 8. So in this
34:56:29
scenario from 10 to 8 we know that 10 is already greater than 8. So we cannot create a substring over here. So let's
34:56:36
ignore this scenario. For the second scenario 7 to 8 actually this is a valid increasing substring
34:56:45
because 7 is less than 8 and uh it comes after it. So what we can determine is
34:56:52
that the longest increasing substring we can make at value number eight would be
34:57:00
whatever the longest increasing substring we have made up until this point. So whatever the longest
34:57:06
increasing substring we have made for the value number seven plus one because
34:57:12
8 is coming after 7 and 8 is just one step after it. So the we can say that
34:57:18
longest increasing substring at value number eight would actually be whatever
34:57:23
we have found up until longest for the longest increasing substring of
34:57:31
7 + 1. And this is how we can determine that this should be solved as a dynamic
34:57:37
programming problem. Because in dynamic programming basically whatever
34:57:43
calculations we make in the past we keep track of them in some way either through an array or storing them in variable
34:57:50
somehow and based on those results we actually use it in upcoming future
34:57:55
calculations so that we don't have to calculate everything from the scratch. So this is one way we can determine that
34:58:02
this problem should be solved do using dynamic programming because if we just
34:58:07
look at the problem we understand that we need to find the longest increasing substring which means that we need to
34:58:13
keep track of whatever we we have calculated so far in the past and using
34:58:18
those results we would make decisions that whether we want to keep this current current value or we want to
34:58:24
ignore this current value. So this is a very important thing to keep in mind and this is uh basically the core concept of
34:58:32
finding the p pattern whenever you are given uh that whether the problem is dynamic problem or dynamic programming
34:58:38
problem or not because in in the interview the interviewer is not going to tell you that hey this is a dynamic programming problem and just go and
34:58:44
solve in that manner. So now let's again continue with our example. So we can
34:58:50
determine that currently the value at uh 8 the longest in the longest increasing
34:58:56
substring we could make at a value number eight is one but we just found that from 7 to 8 we can actually make a
34:59:03
substring as well. So this would become actually two and we can say that up
34:59:09
until the point of 8 the longest increasing substring we can make is actually two and not one. Now let's move
34:59:16
forward. Now let's consider for value number five. At value number five, let's
34:59:22
again compare from 10 to 5. We cannot do anything because 10 is already greater than five. So there is no point of doing
34:59:28
this conversation. Let's again let's compare uh 7 to 5. From 7 to 5 we cannot
34:59:36
do anything because 7 is greater than 5 and also 8 is greater than five. So at value number five there are no values
34:59:43
that are less than five. So the at value number five the longest increasing substring we can make is actually size
34:59:49
one because there does not exist a smaller number before five in our given input. So we will keep this one as it is
34:59:56
because we have already made all the all the calculations. Now let's calculate the for this value number 16 and
35:00:02
actually for value number 16 if you notice that all the values are smaller. So this would be a very good point for
35:00:07
us to understand that how everything works. So from 10 to 16 we notice that
35:00:14
10 is smaller than 16. So there is a possibility and uh basically we can say that whatever the longest increasing
35:00:21
substring we have found at 10. If we do it + 1 that would become 16. So the
35:00:26
longest increasing substring for 10 we have found is actually 1. So 1 + 1
35:00:31
equals to 2. So let's just update the value two over here.
35:00:37
And now let's move on with our calculation. So we are done with this 10. Let's calculate with seven. So if we
35:00:43
do 7 to 16 actually again we will do 1 + 1 uh because lis of 7.
35:00:57
So 1 + 1 is again two. We have already we already have two. So there is no point in updating the value. Let's
35:01:04
ignore this. Let's do again with the value eight. So from 8 to 16 we know
35:01:10
that the value of 8 is actually two. So over here at value number 16 we can say
35:01:15
that increasing substring at value number 8 + 1. So it becomes 2 + 1 and 2 + 1.
35:01:27
Okay, I made a mistake. I think this is one that represents uh
35:01:35
five and the value for 16 is actually over here. So I'll just write it down.
35:01:43
So LIS of 8 + 1 is actually uh 2 + 1 which
35:01:49
is 3 which is greater than whatever the longest increasing sub substring we have so far. So which means we can update
35:01:55
this value. So over here the longest we have found so far is actually three. And
35:02:01
now we can also create one more substring from from 5 to 16. If we
35:02:07
calculate from 5 to 16, we found that the value is actually 1 + 1 would be 2, which is not greater than whatever we
35:02:14
have at 16. So we can say that up until this point 16, the longest substring out
35:02:22
of all of these values we can make is actually three for the values up until
35:02:28
the point of 16. And let's move forward with our calculation.
35:02:34
So again the next value is 27. 27 is greater than all the other values. So if
35:02:39
we do 10 + 20 10 to 27 we would find the value as 2. Uh we'll do 7 to 27. We will
35:02:46
find the value is 1 + 1 again 2. We will do 8 to 27. We would find the value 2 +
35:02:53
1 as 3. Again we will do 5 to 27. The value we would find would be 2. And at
35:03:00
the end we would do 16 to 27. And we know that the value at 16 is 3. So we
35:03:07
would be able to find the value as 3 + 1. And because we have calculated all
35:03:12
these results, we don't have to do calculations all the way from beginning. And we are just able to use the results
35:03:18
we have stored so far. So we know that the maximum value we can find is 3 + 1.
35:03:23
So we would update the value at longest increasing substring at value number 27 to four. And then we come to our last
35:03:31
value 9. So and again we will do the whole thing for 9. So 10 is greater than
35:03:37
9. So we cannot do anything. Uh 7 is less than 9. So we will we can for this
35:03:44
one we can have the value as two. Uh 8 is also less than 9. So from 8 to 9
35:03:51
value we can have would be three. Uh five is also less than 9. So from 5 to 9
35:03:56
the value we would have would be uh 1 + 2 2.
35:04:02
From 16 to 9 we cannot do anything because 16 is greater than 9. And from 27 to 9 we cannot do anything because 27
35:04:08
is uh less definitely greater than 9. Which means that the maximum value we
35:04:14
could have find so far over here for 9 is actually three and that comes from uh
35:04:19
the 8 + 1. So we will update the value over here as three.
35:04:26
And now we just need to find that what is the maximum value we have found in
35:04:31
this uh array that we have created based on the calculation. So basically clearly
35:04:36
we can see that this value four is the maximum value we have found and that would be our answer that would that is
35:04:42
what we would be returning as uh longest increasing substring. The thing is we
35:04:48
actually don't need to iterate over the entire uh entire array again. We could have
35:04:54
actually done this when we are calculating or when we are making this error. We could have just keep track of
35:05:00
one parameter called max and we would compare it with whatever the value we calculate at each location. So whenever
35:05:07
we find a new maximum value we'll just store it in this value and at the end of our loop and this max parameter should
35:05:13
have our uh final solution and we can definitely return this and this solution
35:05:19
would work perfectly fine. Now let's calculate the time complexity. So basically the time complexity for this
35:05:25
one would be big of n² um and it's pretty un simple to
35:05:31
understand that because for every single element we are basically taking all the
35:05:36
elements before that and comparing it with whatever the element we have we did same for every single element. So uh for
35:05:44
n element n we might have to compare it with n minus one values. So the time
35:05:51
complexity becomes big of n². And if we calculate the space complexity, the
35:05:56
space complexity is also big of n because we need to create this additional array to store all the
35:06:02
values. And uh this is a good time complexity and good space complexity
35:06:08
compared to our brute force approach. Remember our brute force approach the value we had was actually 2 to the power
35:06:14
of n which was way higher. This was almost exponential time complexity and
35:06:20
we have done significant improvements from this one and we have actually moved to n². So this solution would work
35:06:27
perfectly fine in any interview and uh I'll move on to coding but thing is I
35:06:33
would be making another video uh to explain that how can we solve the same problem uh using n log n complexity and
35:06:42
this is actually pretty ideal and if you can achieve this in any interview uh if
35:06:48
you if you can come up with this comp time complexity uh right then and there in an interview you can be guaranteed
35:06:55
guaranteed that you would be placed in any company you want. So let's move on
35:07:02
to coding now.
35:07:09
So first of all we will create a new array called lis and we would uh create
35:07:15
the array of size whatever the size we are given for the input nums.
35:07:28
And we will initialize the array with value one.
35:07:39
We will also create a parameter called max uh that will keep track of the
35:07:45
maximum uh maximum longest increasing subsequence inside the loop and we will
35:07:50
initialize the value as one. So now let's create our two loops.
35:07:55
So first of all we'll create a loop that is starting at position number one not
35:08:01
zero because we need something to compare to otherwise all the values would be just uh one before that
35:08:10
and we will run it till the length of the given array.
35:08:23
We will now this would be our inner loop and we would start it from position zero
35:08:28
and we will run it all the way up to the position i.
35:08:37
Now inside the loop first we need to determine that whether our current i that is on the right side of uh the
35:08:43
array is actually lesser is actually greater value than whatever our j is. If
35:08:49
that is the case then only we would move forward with the calculation. So if I is
35:08:54
greater than J.
35:09:00
Now we will do our calculation for the uh dynamic
35:09:06
programming. So the value of I would actually be the maximum value we can
35:09:12
achieve for whatever LIIS of I already have or 1
35:09:20
+ whatever LIS of J we have achieved and
35:09:25
this would be our uh recurrence or relation I guess that is what it is
35:09:32
called in dynamic programming. Uh so this is just to keep in mind that uh yeah if you mention that this is the
35:09:39
recurrence relation it it sounds really good impression sounds cool as well and
35:09:44
uh also we check that whether the current LIS value is our max or not. So
35:09:54
we'll just just check the existing max value with the new LIS that we just created.
35:10:02
And uh yeah, I think that's pretty much it. After this loop runs, uh we can
35:10:08
simply return whatever we have found for the value max. And uh this this should
35:10:14
be our answer. Let's try to run the code. I think we made some silly mistake.
35:10:22
Yeah. Yeah. Looks like our code is working. Let's try to submit it.
35:10:30
And uh our submission works. But if you notice that our submission is not actually the best submission. Uh it's
35:10:36
only faster than 55.54% of the online submissions. And that is because our this sub this solution is
35:10:44
actually work in uh big O of n² times.
35:10:49
So n to the power 2. But uh there is another solution that
35:10:56
actually runs in the go of uh n log n time and I would be uh creating a new
35:11:03
video explaining that uh uh solution and this is actually a pretty interesting
35:11:09
solution. It's actually a sorting algorithm that we are going to use to achieve this. So, hope you like the
35:11:16
video. Let me know what you think and if you have any suggestions, just feel free
35:11:22
to reach out to me. Our goal is to get get employed in any fang company and until we get there, we are not going to
35:11:28
stop. So, hope you like it. Thank you.
35:11:37
So basically the previous previously when I solved this problem I mentioned in that video that I was solving it in
35:11:42
big go of n square time and this would be perfectly good and reasonable to
35:11:48
expect from any candidate uh in an interview but the thing is if you want to be an exceptional candidate if you
35:11:53
want to make sure that you don't leave any gaps uh in your fang journey and your uh so you need to know these
35:12:00
things. So that's why I'm creating this video and in this video we are going to solve this problem in actually big go of
35:12:06
n log n time and the way we are going to do is something called as patient sort.
35:12:20
So let's uh let's take our custom example and as I have mentioned previously that
35:12:28
it is very important to make custom uh examples because using those custom
35:12:33
examples you can determine that you have the ability to think and uh make sure
35:12:39
that uh how can you create your own test cases.
35:12:45
So this is our example and uh it's quite a long one but the
35:12:51
thing is I need I need to make sure that I go through all the possible aspects in
35:12:57
the given example and that's why I took so many inteious so it becomes
35:13:02
absolutely clear in my in your mind that how you are how we are going to achieve it. So basically at any given location
35:13:11
we can either have a null string. So a subsequence that has no no entries. Uh
35:13:18
subsequence that has just one entry. A subsequence that has two entries. So
35:13:24
this is null. One entry two entries. Subsequence that has three entries.
35:13:29
Subsequence that has four entries and so on. So and our aim is to find out
35:13:36
longest increasing subsequence that we can achieve. So
35:13:41
for this one we are going to use couple of arrays we are going to put them in a
35:13:48
different manner and uh as you would have guessed that because the time complexity we get is actually n login
35:13:56
somehow we are going to use binary sort over here. So let's start the uh let's
35:14:01
start the problem. First of all we are going to create two arrays. Uh first one first array is to
35:14:10
keep track of the longest increasing subsequence that we have found. So whether it's value of value one of value
35:14:17
two of value three whatn not and second thing is we are going to store the last
35:14:23
digit for any given longest increasing subsequence. So what I mean by this last
35:14:28
digit is that suppose we find a long an increasing subsequence over here that
35:14:33
the values five 16 and 27 is uh an
35:14:38
increasing subsequence. So in the longest increasing subsequence array we are going to note an entry as three
35:14:45
where the because the length of values are three and the last entry we have in this sub subsequence is 27 and the
35:14:54
combination of these two is going to allow us to create some pretty interesting things. So let me go over
35:15:00
the example and I would be explaining every single time what we are doing and
35:15:06
uh how we are finding it and at the end I'm going to show you that what could be the intuition behind this.
35:15:12
So at first location 10 basically we don't have any any substring so far. So
35:15:20
the current substring we have found up until this point 10 is just a single
35:15:25
value uh 10 and in this single value 10 in our LIS we can create an entry like
35:15:33
one and the last digit we have for this entry one is 10. So we are good so far.
35:15:40
Now let's move on to the next one. Now next entry is uh so currently we only
35:15:47
have a substring 10. Next entry we have is seven. Now we
35:15:54
cannot create an increasing subsequence just just by these two pairs because uh
35:16:00
obviously 10 is greater than seven. But the thing is uh we can replace this 10
35:16:06
with this seven. And how we can replace it is because
35:16:11
up until this point 10 is a substring of length one and seven is also a substring
35:16:18
of length one. So both of us are the same. But the thing is whenever we move forward
35:16:24
all the values that are greater than 10 will also be greater than 7. Which means
35:16:31
that suppose we have value over here 11 15 18 something like this. And if we
35:16:37
take it with 10 we would be able to create a longest increasing sub substring like 10 11 15 18. The thing is
35:16:45
same thing can be done for seven as well. So it makes no difference that which entry we keep. But if we have a
35:16:52
value that is between 7 and 10. 10 won't be able to do anything in that case.
35:16:58
Suppose we have an entry like uh 8 9 11. So in this case if we would have just
35:17:05
considered 10 the longest sub substring we would be able to make is 10 to 11. That's it. But from 7 we can actually
35:17:11
make 7 to 8 8 to 9 and 9 to 11. This would be of size four and this would be only of size two. So it is in our
35:17:18
interest to keep seven as our longest increasing substring and not 10 because
35:17:25
uh value of seven is actually less than it. So we will replace this 10 in this uh in this two array we have created. So
35:17:35
currently the last element we have becomes
35:17:40
seven and this uh seven is also of just
35:17:46
uh length one. So we have only kept this one entry and we have basically just
35:17:51
discarded it. We have went over it and we didn't find anything good. Now at
35:17:56
this point we only have a substring of seven. Now comes the value 8. Now 8 is
35:18:02
greater than seven and 8 is in itself a
35:18:09
higher value. So we have now we have two possibilities. Either we have we can
35:18:15
keep seven as it is as a longest increasing subsequence
35:18:20
or we can have a subse subsequence like seven and 8 and we are not appending 8
35:18:28
behind this seven. We are creating that the longest increasing subsequence we have so far of value of size one is
35:18:36
still seven. But this one is we are creating a new subsequence that is of
35:18:42
size two and we have we are appending this seven behind 8. So which means we
35:18:48
would be creating a new entry over here in our longest increasing subsequence of value two and the last element of this
35:18:56
value is actually eight. The thing is meanwhile the first element is still
35:19:01
seven because we only up until this point if we consider a substring that is
35:19:07
of only value that is to be only of size one the best element to choose for size
35:19:13
one would be seven because it is the smallest and this is the main logic
35:19:19
behind the patient sort. So let's move on to the next element.
35:19:27
Again we go to value five now and the substrings we have so far are seven
35:19:34
7 and 8 and now we have this five. So
35:19:41
we cannot append this five over here. We cannot do anything with this. But the thing is if we consider these four
35:19:49
elements and if we consider the substring of size one five would be the
35:19:54
most ideal candidate and not seven because five is actually less than seven. So it is in our interest to
35:20:00
replace this entry 7 with the entry five. And we will update in our uh
35:20:10
in our uh array with entry five.
35:20:18
Let's clean this up a bit. Now due to space con constraints we are going to
35:20:24
write down our sub uh subsequences over here. So so far we have to found two
35:20:30
subsequences. One is just five that is of size one and second one is 7 and 8 uh that we have
35:20:39
stored stored over here and we have we are keeping track of the last digit that we have appended.
35:20:45
Again let's consider 16. So now for this 16 six and if we consider the last two
35:20:52
elements 16 is definitely greater than five but there is no point in appending 16 at five. It is in our best interest
35:21:02
to append 16 behind this 8. So our
35:21:07
algorithm is basically what we are doing is we are taking the value from the input. We are checking in our uh last
35:21:16
array to see that what is the best position to fit that value. And the best
35:21:21
position to fit that value is to keep it keep the increasing order
35:21:27
intact because notice that previously the value we had was 7 and 8. That was
35:21:32
increasing order. Now the value we have is 5 and 8. that is also increasing order and now the next value seven next
35:21:38
value 16 comes we can actually append it behind eight. So after eight we can
35:21:44
create a new entry and we would do that. So we would create a new entry called
35:21:49
three. And why we were able to do a new entry is because this seven and 8 we are
35:21:54
not going to replace 8 by 16. We are actually going to leverage this seven and 8 because they are already a
35:22:00
subsequence and our aim is to find the longest increasing subsequence. So why would we replace 8 with 16? It's
35:22:06
actually in our favor to keep this 8 7 and 8 and create a new subsequence 7 8
35:22:14
and 16. So that we can use because suppose
35:22:20
if all the values that come after 16 are like 9 10 11 12 13 and if we have
35:22:28
created a subsequence called uh 7 and 16. So these all values we would not be
35:22:35
able to consider them as our longest increasing subsequence because we don't have this eight. But if we have this uh
35:22:42
7 and 8 over here and if these values comes after 16 and we have created a
35:22:47
separate entry like this one 7 8 and 16. So this is separate in itself. We can actually append all these 9 10 11 12 13
35:22:54
values behind this uh 7 and 8 and this would be our longest increasing subsequent. So I hope that this makes
35:23:01
things uh more clear that why we are choosing to have a new uh 7 8 and 16 as
35:23:07
substring and we would we would create a new entry in our array as well. So now
35:23:14
these are the three substrings we have. Next value is 27. So 27 is again greater
35:23:22
than this uh 16. So now we are going to create a new entry 7 8 16 and 27
35:23:31
and we are going to have a new entry in our LIS with value number four and we
35:23:38
are going to add the last digit as 27 over here. I hope that uh what I'm doing
35:23:43
is understandable that why we are actually creating this new entry uh from
35:23:49
the given input.
35:23:56
The next value we have is nine. So let's see that where is the best place we can
35:24:02
fit this nine. The best way the best place we can fit this 9 is actually
35:24:08
after 7 and 8. So like this 9. The thing is we are not going to replace the seven
35:24:15
and 8 with 9 because up until this point up until 9 if we see the best pair with
35:24:25
two entries only that with the least value is actually seven and 8. There are
35:24:32
multiple pairs that create the val uh that are creating the longest increasing
35:24:38
subsequence of length two u like five and 16 16 and 27 5 and 27 the thing is
35:24:44
they're all greater values if we see the last element over here 7 and 8 the last
35:24:50
element is the perfect fit so that is why we are going to keep the seven and 8
35:24:58
and we would be creating a new entry at this replace. So we are going to replace
35:25:03
this 16 with value number 9. So let's update this in our array as well. So for
35:25:09
the value three the best we can find
35:25:15
is 9 and that would be the subsequence 7 8 and 9. So, so far we are keeping track
35:25:21
of all the subsequences that we have found with the values 1 2 3 and four and
35:25:28
we are also keeping track of the last digit that we have calculated so far. And because all the values are in an
35:25:35
increasing order, it becomes very easy for us that whenever we find any new
35:25:41
value like this, uh it becomes pretty easy for us that where we are going to
35:25:47
add it in this uh array and which uh value we are going to update it. So this
35:25:54
is the main logic behind patient sort. Now the next value is value number one.
35:26:01
So where in this array we can store value number one? It's pretty simple. We can only store it at position one. No
35:26:08
other position we can store. And based on this we can say that up until this point if we only have to create a subse
35:26:15
subsequence of length one, it would be the most ideal to have the last digit as one because all the values after that
35:26:21
would actually be uh in an increasing order and we can replace this by
35:26:27
in our list of subsequence. we will have entry one over here.
35:26:34
Now let's consider this value number 13 where over here we can add this value
35:26:40
number 13 so that it would give us the most value and actually we should not be
35:26:46
replacing this 9 with value number 13 because we are not trying to achieve a
35:26:52
substring like this rather than having 7 8 and 9. We are not trying to get 7 8
35:26:57
and 13 because that is not in our favor because notice that this is already existing and 13 can be appended uh next
35:27:04
to it. So what we can do is actually we can replace this four what the
35:27:10
subsequence with four entries with this 7 8 9 and 13. So our new subsequence
35:27:17
would become
35:27:22
7 8 9 and the value 7 8 9 and 13. And why we are able to replace the 7 8 9 and
35:27:30
13 with previously 7 8 uh 16 and 27. The
35:27:35
reason is quite simple because both generate the value four. So that is
35:27:40
okay. But the thing is with this 9 and 13 we have higher odds of making longest
35:27:47
increasing subsequences for the upcoming values and which we are going to see right for with the next value. So we
35:27:54
will update the value 13 over here
35:28:02
and so far so far these are the four subsequences
35:28:08
we have. Now the next value is actually 15. And imagine that if we had kept this
35:28:14
value as the substring of four values, we wouldn't be able to insert 15 over here because though both of these were
35:28:23
same, 15 is easier to be appended over here but it cannot be appended over
35:28:29
here. So that is why in the previous step we actually replace this value four with 13.
35:28:36
So I hope this makes it uh more understandable. Now let's see that what we can do for this uh value number 15.
35:28:44
So the logic is quite simple. We are simply going to append this value number
35:28:51
15 behind this 13. So the new substr and
35:28:56
we are again we are going to keep the value number uh 7 8 9 and 13 as a four
35:29:03
substring as a substring of length four. And we are going to create a new substring 7 8 9 13 and 15. And this
35:29:12
would be a new entry in our array. So we will have a substring of length five. And the last digit for that would
35:29:19
actually be uh 15. And this would be the end of our array.
35:29:26
Uh and since we have reached to the end, we just need to iterate over this one
35:29:31
and find out that what is the biggest length we were able to find. And we just simply return this value. So this is as
35:29:39
simple as it can be. And why we are able to achieve it? Because at every single
35:29:45
location for every single element we are trying to see that where we can fit that
35:29:50
element that best represents that position and based on it we were keeping
35:29:55
track of the longest increasing subsequence. So basically we were intellectually choosing our own longest
35:30:02
increasing subsequence and we are also keeping track of whatever we have calculated in the past because if we
35:30:08
were to choose a value of three that what is the longest increasing subsequence up to the point of three we
35:30:14
can easily say that hey it's this one and the last digit is actually 9. So if we find um some better digit it becomes
35:30:22
pretty easy uh for us to calculate that where we are going to append that value.
35:30:28
And I hope this makes things uh more understandable. Now let's calculate the
35:30:34
time and space complexity for this one. And it's pretty simple that at any given
35:30:40
location we are iterating over the entire array. And for any single position we are checking that where we
35:30:47
can store that position in this given uh new array that we are trying to create. But the thing is this new array is
35:30:53
already sorted. So if it because it is sorted we can actually achieve that in log time and initially we have to
35:31:01
iterate over this entire actual input once. So that will take n times. So
35:31:06
basically we are calculating this whole approach in big go of n login time which
35:31:12
is a very good com time complexity because if you remember correctly originally the brute for the brute force
35:31:18
approach our time complexity was 2 to the^ of n for the uh second accepted
35:31:25
approach that I completed in last video our time complexity is actually n² the
35:31:31
thing is n login this is a thing of beauty now let's move on to coding and
35:31:37
if you still don't understand the concept I again ask you kindly to go
35:31:43
over this example again because if you can master this sky's is the limit for
35:31:49
you. So let's do the coding now.
35:31:55
Let's create a new array list.
35:32:01
We can start by adding the first element because uh
35:32:07
the first element would actually be the first uh list of uh size one
35:32:20
and then we will initialize our loop to iterate over the entire input array and again we will start the loop from uh
35:32:27
second position i = one inside the loop we need to find that
35:32:33
whether the given number is it actually greater than whatever the last value we
35:32:39
have in this subsequence if it is we need to append it to the subsequence so
35:32:51
and we can just add it to the subsequence
35:32:58
if not we'll need to run the binary search. So
35:33:06
and over here we can just create a new function for to run our binary search
35:33:17
and input we will provide uh the substring and current uh value we have
35:33:26
and now let's create method for it
35:33:37
inside the loop. First of all, we'll create a left and right variable. So left would be of size zero and uh
35:33:46
right would be of whatever the size we have for the
35:33:51
uh integer for the given in substring.
35:34:05
Now we will just run a condition that while left is less than right.
35:34:12
We are going to calculate the midpointer and then
35:34:17
if the midpointer
35:34:29
is already existing, we simply return that value.
35:34:37
If not we either move on the left side or right side. Oh,
35:35:00
we'll do left is equal to mid + 1.
35:35:06
else we can simply do right is equal to mid
35:35:13
and after the loop we can return the value of left.
35:35:20
Now over here in the J we are receiving whatever the value of left we got. So we
35:35:25
add the subset to uh
35:35:31
our existing subsequence
35:35:38
that that should be the logic. Uh so after the return we after uh the end of
35:35:43
the loop we just need to return the size of the list
35:35:49
and this should provide the longest increasing subsequence. Let's try to run this code.
35:36:03
Looks like we put the values out of order.
35:36:09
Yeah, looks like our solution is working. Let's try to submit it.
35:36:16
And yeah, see our solution is actually faster than lot of other submissions. And uh that is because we are our
35:36:21
runtime is actually n login and uh I'll be posting this solution in the comments
35:36:27
and I hope you like the video. Thank you.
35:36:40
So the lead code problem we are going to solve now is called longest common subsequence. Now we can see that this
35:36:45
one is a lead code medium problem and also one of the most liked problems on lead code. So I'm going to pay my utmost
35:36:51
attention. Now let's understand the statement. We are given two strings called text one and text two. Now we
35:36:57
need to return the longest common subsequence. And if there is no common subsequence that exists then we need to
35:37:03
return zero. Now we are given the definition of a subsequence is a string that is a new string that can be
35:37:10
generated from the original string with some characters that can be deleted
35:37:15
without changing the relative order of the the characteristics. So without getting too much into the details of the
35:37:22
definition let's try to understand what we are being asked to solve. Basically we are given two strings text one and
35:37:28
text two. Now we can notice that text one currently has five characters A, B, C, D, E and text two has currently three
35:37:36
characters A, C and E. Now the thing is if say for an example from text one we
35:37:42
decide to eliminate this characters B and D we can also create A C and E and
35:37:48
this is going to be the exact same manner or the sequence of relative order
35:37:54
remains the same between both the strings. So we can say that for this given example we actually have a longest
35:38:01
common subsequence that we can make that follows the relative order and that is of size three. So we need to return
35:38:08
three as part of the answer for in this case. Now let's try to understand it with one more example for this one. Now
35:38:14
we can see that currently the characters we have is xyz and the characters we have for this text 2 is yab. So now we
35:38:23
can only find one character that is common between both of them and that follows the relative order and that is
35:38:29
this Y. Apart from that we don't see anything common. So in this case we can only create a longest common subsequence
35:38:36
that only cont consist one character. So we need to return one as the answer. Now
35:38:42
if we take a look at this example text one and text two we see that there are no characters that are same between both
35:38:49
the text. So in this case we will have to return zero. But in the same example say for some reason if we are given the
35:38:56
values like a b c and d e f over here and then we are also given d e over here
35:39:01
then we will need to return two as the answer because the relative order of d and e remains the same even if this this
35:39:08
string had three additional characters. So we will have to solve this problem and definitely this is going to yield to
35:39:15
some very interesting results. Now let's understand the brute force approach to solve this problem. The logic is quite
35:39:22
straightforward. Let's say that we are currently given two strings uh in this particular fashion. Then we what we can
35:39:29
do is we can go through every single possible combination of any particular
35:39:35
string and try to match it with the other string. So what I'm suggesting is that for this text one we start taking
35:39:41
permutation of all the other substrings that we can make out of this one. And we
35:39:47
know in terms of making permutations we can sum actually make 2 to the power of n permutations for any given value. Why?
35:39:55
Because at every single character we will have to make the decision that whether we need to include this character or not to include this
35:40:01
character in order to generate the permutation. So this would eventually yield us the correct result because what
35:40:08
we'll do is we'll try to create all the different permutations and combination compare it with this given another
35:40:14
string and we'll try to see that what is the longest common subsequence that we are able to make but this is very
35:40:20
inefficient approach and also the time complexity goes in some sort of exponential form so I'll not go into the
35:40:27
depths of this one and we'll try to do something smart in order to solve this problem. Now let me come to the optimal
35:40:34
way to solve this problem and for that we are going to use one of the most beautiful concepts in computer science
35:40:40
and that is dynamic programming. Now let's take a quick recap. Let's
35:40:45
understand that why do we actually have to use dynamic programming in this problem. Well the answer is actually
35:40:51
quite straightforward because let's say that we are currently given the two strings as a b cde e and then once again
35:40:58
a c and d. Now notice that if we start comparing the two strings at any given
35:41:04
moment character by character it would not be very much fruitful. Why? Because okay let's say that we define that this
35:41:11
A is common between both of the subsequence. Now we are at this character B and we don't know that next
35:41:18
character B is not present over here. So we don't know that whether B is going to be present somewhere down the road or
35:41:25
not. So do you think that we should compare B with every other character that is currently present inside the T2
35:41:31
string? Well, we could do that and we are going to do that. But in order to do
35:41:37
that, we'll also have to remember that what was the relative order of sequence that we have been able to identify
35:41:43
beforehand. And it could be possible that if we are dealing with multiple sequences, which subsequent to consider.
35:41:49
So let me give you one example like this. Let's say that we are given currently strings like a b cde e okay
35:41:56
and we are given the t2 string string to be a b then x y z and then once again we
35:42:02
are given the string to be let's say uh b c d e so do you think that from this
35:42:09
particular point forward if we see the longest common sequence we can make is going to be two but the moment we start
35:42:16
identifying these characters we can if we just drop this B we can actually
35:42:21
create the longest common subsequence of size five. But we have to drop one B
35:42:27
that was already part of one of our relative subsequence. Which means the
35:42:32
result that we are going to make later down the road is actually going to be dependent on the previously calculations
35:42:39
that has been made and also future calculations that we are yet to be make and when we are at the last position we
35:42:46
should make the best judgment on which path to take. So that's why this is a good candidate for dynamic programming.
35:42:53
Now the question is how we are going to use dynamic programming to solve this problem and for that what I'm suggesting
35:43:00
is number one we have to check every single character for all the other
35:43:05
characters and same way for any particular character we will have to compare with compare it with all the
35:43:11
remaining characters. So there is no getting away from that in this problem. we will have to do n² work or multiplied
35:43:17
by n work where m is the length of text one and n is the length of text 2. Okay. So this is this has to run in big of n²
35:43:25
time complexity. But how we are going to do that? Number one thing I'm suggesting is that we actually create an m cross n
35:43:32
grid just like the one that I have shown over here. And for this particular grid we'll need two things for for our
35:43:39
dynamic programming. We'll need a base case scenario. So base case is quite straightforward that if any particular
35:43:45
character is not matching with the other character then we simply define it as zero. And notice that we actually have
35:43:52
created an extra space uh at the beginning. So there is an extra row and
35:43:58
extra column which means this is not strictly an M crossN matrix. This is actually an M + 1 multiplied by N +1 uh
35:44:06
matrix. So we are adding one more extra line and that is to consider our base
35:44:12
case. Now at any given moment what we are going to do is if we identify that
35:44:18
there exist a combination there exist a value that is common. Let's say that over here the C and C is going to be
35:44:25
common for this particular cell. Which means what we can definitely say in this case is that this cell is going to be an
35:44:33
addition to the previously calculated longest common subsequence. Now what is
35:44:38
going where is going to be that information for the longest common subsequence to the diagonal value. Why
35:44:43
it would be at the diagonal value? Well, let's take a simple example. Let's say that currently the values are a b c and
35:44:49
this value is a b and c. So notice that for this particular square the logic is
35:44:54
going to be quite straightforward. We are going to have a and a common at this place. Then we are going to have b and b
35:45:00
common at this place. And then we are going to have c and c common at this place. Which means longest common
35:45:05
subsequence is directly represented towards the diagonal value in the best case scenario. And this is the fact that
35:45:12
we are going to exploit. So whenever we identify that at this particular location there was a common subsequence
35:45:19
then we had to add one value to the previously found longest common
35:45:24
subsequence. But we haven't found any subsequence because this value is zero. So definitely the longest common
35:45:30
subsequence at this eighth location is going to be one. So we are going to mark it by one. Same way the longest common
35:45:37
subsequence at this location is actually now two because we are comparing AB with AB and that's why this is going to be an
35:45:45
addition to the diagonal. So we are going to mark value two and same way this is going to be value three. One
35:45:51
more addition. So same logic we are going to apply over here that whenever we identify any particular common
35:45:58
characters we will check the diagonal value that is number one thing. Next thing is that let's say we identify any
35:46:06
particular character that does not have any common values. So both characters are different than each other. Then it
35:46:12
becomes the question that what is the longest common subsequence we have found so far and there can be two
35:46:19
possibilities. Why? Because let's say that I'm currently at this B position. So on one side I'm checking against AB.
35:46:27
But for AB I have checked with A. I have checked with A C and I have checked with
35:46:32
AC because I'm trying to fill up this row. Same way for any particular C
35:46:38
character. I'm also comparing it against A against AB against ABC and whatnot. So
35:46:44
the answer for the longest common subsequence where the characters do not match is actually going to reside on the
35:46:51
adjacent cells for any particular cell. So let's say I'm trying to consider the values for this cell. Now we know that B
35:46:57
and C don't match. So in this case we'll have to check that what is the longest common subsequence we found either way
35:47:04
because we are not only comparing text one with text one or text two with text two. We are comparing them with each
35:47:10
other. So we'll have to take the maximum value amongst the adjacent cells and this is going to yield us the correct
35:47:16
result. So now let's recap our rules. Number one, if we find equal characters,
35:47:22
so let's say that if an i and j value are equal, then we are going to do the +
35:47:27
one operation compared to its um diagonal value. So diagonal value is going to be i minus one and j minus one
35:47:35
uh this cell. Okay. And if that is not the case, if we find that I and J character do not match, then we will
35:47:42
have to find the maximum value from its adjacent values or subsequent neighbors.
35:47:47
So now let's try to do the solution right now. Okay, let's start filling up
35:47:52
this particular whole matrix. Now very first value we find a and a there is a
35:47:58
match. If there is a match, we are going to compare it with its diagonal value and add one. So diagonal value is zero.
35:48:04
So we are going to add value number one over here. Now next thing is that we will also have to check uh let's go row
35:48:11
by row. So now we are checking this A with this value B. A and B do not match. So if they do not match we'll have for
35:48:18
this cell we'll have to check its neighbors. So we check this neighbor and this neighbor and whichever is the
35:48:23
maximum value we add this one. So what we are saying is that up until this point inside our uh input we have
35:48:31
calculated a b with a. So in this text one and text two we can see that the
35:48:37
longest common subsequence we find was of size one and this is what we are defining it over here. Next we are
35:48:44
comparing a with c once again uh sorry a with c once again there is no commonality so we'll add value one. A
35:48:51
with D once again no commonality. So we will add the maximum value one and A with E once again the maximum value is
35:48:58
going to be one. Now let's repeat the same operation once again. But now this time we are going to be doing it for
35:49:04
value C. Now C and A do not match. So we'll try to find the maximum amongst
35:49:10
these two value. And once again the maximum value among these two is still going to be one. So let's just mark it
35:49:16
as one. Same way this is going to be one as well. Now we are at this position of
35:49:21
C matches C. So we'll have to do an increment with the diagonal value and we
35:49:27
are going to be adding plus one over here. So we can mark this as two. Now for this D with C we'll have to compare
35:49:35
the maximum amongst these two and the maximum value is two. So we'll mark the value as two as the answer and same way
35:49:42
two as the answer over here. Now we are comparing E with this A. So once again
35:49:47
the maximum amongst these two value is going to be one and notice we found two over here but why we are marking one
35:49:53
because notice what we are calculating or comparing so far we are comparing a
35:49:59
with value a c e. So in this case the longest common subsequence is going to
35:50:06
be of size one and that's why we are marking one over here. Same way this is going to be one because we are comparing
35:50:12
the maximum amongst these two. Same way with C we are go the now the value is
35:50:17
going to be two because this value was two and why it was two because notice we are comparing the values A B C versus
35:50:25
value A C E and amongst this comparison we can see that there exist the longest
35:50:31
common subsequence of size two that which is represented over here this is the beauty of dynamic programming
35:50:37
solution now uh for this D comparing with this E once again we'll choose the
35:50:43
maximum So answer should be two. And now we have E common for this last cell. So
35:50:49
we'll have to do + one with the diagonal. So 2 + 1 is going to be three. So we'll mark it as three. In the end,
35:50:55
we simply need to return whatever we find in the very last cell as part of the answer and that is going to be uh
35:51:01
three in this case. So we can return this with confidence. See how beautiful the solution looks. All we need to do is
35:51:07
just fill up this matrix and things work out beautifully for us. Now if we have
35:51:12
to calculate the time and space complexity for this one, time complexity is going to be big of n² or m * n and
35:51:20
space complexity is also going to be big of uh m + 1 * n + 1. So we can say m
35:51:28
cross n for simplicity. But anyways this is a beautiful time and space complexity and very awesome approach. Now let's see
35:51:36
the coding solution for this problem. uh basically we are going to define two characters m and n to define the length
35:51:43
of both of the given strings text one and text two. Then we are going to initialize our new array uh dp array.
35:51:50
Now notice that we are defining it as an length of m + 1 and n +1 to take care of
35:51:56
the zero case scenario that is going to be our base case for our dynamic programming table. Now uh for this
35:52:03
matrix we are going to fill in all the details. So we are going to use two for loops to iterate over every single row
35:52:08
and every single column. Notice that we are starting the values from one and one because for i value of zero and j value
35:52:15
of zero we already defined the values as zero. Now first thing we are checking is that at any given moment we identify
35:52:23
that the character at i minus one and character at j minus one location are equal to each other. Then for the
35:52:30
current I and J value we are going to add one to the existing diagonal value
35:52:37
that is I -1 and J minus one value inside the DP array. If that is not the
35:52:42
case then we are simply going to pick whichever is the maximum value for any particular I and J element from its
35:52:50
adjacent neighbors. So whether the top value or the left value of any given cell and in the end we should have
35:52:57
completed all the values for the longest common subsequence and the very last element inside our DP array is going to
35:53:04
represent that. So we are simply going to represent that value that should give us our correct longest common
35:53:09
subsequence. So now let's try to run this code.
35:53:15
Seems like our solution is working as expected. Let's submit this code.
35:53:21
and our code beats almost 90% of all the other solutions. That is excellent in
35:53:27
terms of time complexity. Now for the memory, we can improve on some aspects. Uh but we are using like an M cross grid
35:53:34
and that is also a fine enough solution but overall this is a beautiful solution and once again it is available on our
35:53:40
GitHub repository. So feel free to go ahead and check it out from there. Thank you.
35:53:54
Hello friends, we are still not employed by fang company. So let's not solve late coding till we get there. Today we are going to do a very important lead code
35:54:00
medium problem word break. Uh let's understand the problem statement. So basically we are given a string s and we
35:54:07
are also given a dictionary of string word dict and we need to return true if s can be segmented by all the words that
35:54:14
are given inside the word dick. So if we look at the example suppose our S is
35:54:19
lead code and the verdict we are given is uh first
35:54:25
set is lead and second set is code.
35:54:32
We can clearly see that this lead code we can generate from whatever we are whatever the values we are given in this
35:54:38
dictionary. So we will return true in this case and we are also mentioned that we can use the same word multiple times.
35:54:45
So suppose if this problem was lead code lead uh code uh something like this we
35:54:52
would still return true because um all whatever words are we can still make it through this dictionary. But if we were
35:55:00
given some wording like this that lead code L E. So up until this point we have the
35:55:09
words that we can make from this uh dictionary. The thing is this le e there is not a specific word given for that.
35:55:16
Uh the word we are given in the word dictionary is lead. So it does not match. So in that scenario we would
35:55:21
return false otherwise we would return true.
35:55:27
Okay let's try to understand that what would be the brute force approach. Suppose we are given s is equal to e s
35:55:32
pn and the dictionary we are given is uh e s p and n. So we can clearly see that
35:55:40
all the words we can are present in the word dictionary. So the answer should be true. Uh and uh in the brute force
35:55:47
solution we are going to use a bottom up approach. So uh and in this uh video I'm
35:55:55
going to show bottom up approach all the way um even for the optimal solution. So this can also be solved as a top down
35:56:01
approach. So let me know if you want to make a separate video on that. Uh and there is also one more thing to
35:56:07
consider. Suppose we are given something like s is equal to null value or empty string and in the word dictionary we are
35:56:14
given some elements like a b a b blah blah blah. So this case we can clearly
35:56:20
return as true. Why? Because this empty element will always be there. uh though
35:56:27
it might not be showing but the thing is if there is if there are no elements in our given string the we can always
35:56:34
return true because the emptiness is all also exist in this word dictionary. So
35:56:39
we are going to use this logic and uh let's see that how we can build our uh B
35:56:45
brute force. So we are doing bottom up. So we are starting from the lowest value and eventually we are going to make the
35:56:52
whole world. So the first value we need to so we are at the zero position. The
35:56:58
first value we need to make is uh simply the word break of a value e and the word
35:57:06
break of value e is very easy to calculate. U we only need to check that whether the word break of a empty string
35:57:14
and the value e exist in this given word dictionary or not. So basically and we
35:57:20
know that if there is an empty string scenario this will always be true because I just explained it to you how.
35:57:27
So we only need to see that whether this E exists in this word dictionary or not. If this exists we can clearly say that
35:57:33
this is true and the we can uh denote the value of word break of E as true.
35:57:39
Now the second option we second decision we can make over here would be to see
35:57:44
the word break of two elements. So E and S and how can we determine the word
35:57:50
break of E and S? Uh well again it's simple. So we need to we have two ways to determine that either we can do a
35:57:57
word break of empty string and we can check that whether this E s value is
35:58:03
present in this word dictionary or not or we can do a word break of value e
35:58:08
because we know that this is always true. The word break of empty is always true. So we can do a word break of e and
35:58:14
we can check that whether the value uh s is present uh in this given word
35:58:20
dictionary or not and word break of e we already know how to do it for this word
35:58:25
break of e we need to do word break of empty and we need to calculate the value
35:58:30
of uh to see that whether this e is present or not. The third option over here we can have is uh and you guessed
35:58:38
it correctly the word break of three elements. So ESP and for this three elements we again
35:58:45
have three more possibilities. So word break of empty string and uh we need to
35:58:50
check that whether ESP all these three exist in this uh scenario or uh we need
35:58:56
to check that whether the word break of uh whether the word break of this uh E
35:59:05
and SP exist and the word break of E S
35:59:10
and P exist and yeah so these are the three ways we can determine that whether the word
35:59:16
break of ESP exist. Uh the next option we have is uh the final scenario that
35:59:22
whether the word break of ESP exists or not. And to check that we we will have
35:59:30
four possibilities. So first one is that we check the empty string and we check whether the espn the whole word is uh
35:59:38
present in this word dictionary or not or we can check that whether the word break of e is present and spn these
35:59:47
three values are present or not or we can check that word break of e s is present and we can check for pn or we
35:59:55
can check word break of e s and we can check the value n. So these would be the
36:00:01
four cases where we need to calculate all of these and for every single one of them. So even in order to calculate this
36:00:07
word break of e we will use uh uh this method to calculate this word break of e
36:00:13
s we will calculate this uh whole method and uh yeah so this would be the brute
36:00:20
force solution. Eventually we would find that uh whether we are able to make this ESPN or not and uh whatever result we
36:00:28
get we just need to bring it upwards and we would be able to find the solution.
36:00:33
So this solution works but it works in a very horrible way because at every single location we have two
36:00:39
possibilities to make whether we want to keep that uh element or not whether we want to keep that element or not and our
36:00:45
decision tree keeps on growing and growing and growing and though we will come uh to the correct solution but it's
36:00:53
going to take us a lot of iterations to achieve that because over here you can see that we only had these four elements
36:00:59
uh that we need to consider. we generated such a big tree and over here most of the values we did not even
36:01:05
completed the whole uh sub iteration for them because it's going to I would be
36:01:10
running out of space. So the time complexity as you have guessed correctly
36:01:16
for this approach is actually big of 2 to the power n because at every single location we are making two decisions
36:01:23
which is pretty bad and why it is 2 to the power n because we are calculating everything at the same time. So see that
36:01:31
do we have a room where we can save whatever we have calculated before and can we use it further down the road? Of
36:01:37
course we can because notice over here this W word break of E we are using it
36:01:43
over here but we have already calculated its value. So why do we need to calculate its value again over here? Same goes with word this word break of E
36:01:50
S we have already calculated the value over here. So why are we repeating this whole process? There are lot of repeated
36:01:57
effort. This is repeated. This is repeated. This is repeated. We have already calculated all these values. So
36:02:04
somehow if we just create a cache, we store that whatever the values we have calculated so far and keep track of that
36:02:11
cache and whenever we need to encounter that uh whatever value we are
36:02:16
calculating right now, we can simply check that whether that has already been calculated and uh using that we can
36:02:23
actually come up to a better solution. Since you guessed it correctly that
36:02:29
because we are using something that we have already calculated in past we are keeping it keeping a track of it in some
36:02:36
form and we are using it further down uh in our next iterations. So basically we
36:02:41
are using the most beautiful thing in the computer programming the dynamic programming approach. In the dynamic
36:02:47
programming, we are going to create a single array of size whatever the input
36:02:52
given input string is and uh based on that particular array we will calculate
36:02:59
all the values that have been calculated so far and because this is a bottom up approach we are going to uh start
36:03:06
filling up array from the zerooth position and we will reach reach at the end and in the end after all the
36:03:13
calculation we will just simply return whatever the value we I have calculated over here. So let's see that what would
36:03:19
be the optimal solution. Suppose again we are considering the same example S is
36:03:24
equal to E S PN and the word we are given is E SP and N. And now let's
36:03:33
create a new data structure uh called uh DP of an array that is of size four and
36:03:42
uh there would be so 0 1 2 3 4. Now we
36:03:48
know that this zeroth position uh would always be true
36:03:54
and uh why it would be true because this indicates that for DP of size zero which
36:04:00
means that for string of size zero uh does it does the word dictionary
36:04:06
contains this particular element or not. This is what this dp is representing
36:04:12
that every at every single location whether the value of u that length of
36:04:18
the character is it present in this word dictionary or not. So dp of0 zero we know that that's an empty string and if
36:04:25
it is an empty string we can determine the value is true. So this would become our base case and this is very important
36:04:31
to identify in a dynamic programming problem that we need to have a base case and uh initially we would set up all the
36:04:38
other values as false and we will run our iteration. So let's see that what
36:04:45
each each of these values are going to represent and you guessed it correctly that this value represents a word break
36:04:52
of zero. This represents the word break of one. So in this case it would be the value E.
36:05:00
This represents the word break of value E S. This represents the word break of
36:05:06
value E SP. And this one represents the whole word. So word break of the value E
36:05:14
S PN. And uh yeah so at the end whatever we
36:05:20
whatever result we find over here if we just return that that would be our perfect solution. So example we are
36:05:26
going to take is the same one that we have been uh discussing. So uh the s is espn and the value of word is e sp and n
36:05:38
and we know that our uh dynamic programming of value zero. This is our
36:05:44
base case that is true. So what we are going to do is we are going to iterate over
36:05:52
starting from single element we are going to keep on increasing the size of our element depending on the size of our
36:05:59
element we are going to fill up this DP array and uh at the end we will just return the value. So initially we will
36:06:07
have we will calculate for just for value e. So dp of 1 would be calculating
36:06:14
the word break for value e. So let's see that whether this value e is present in this uh word dictionary or not. So the
36:06:21
value is present. So we can say that the dp of 1 is true.
36:06:27
Okay, this is good. Now let's check for the second element. So uh for dp of e2
36:06:37
this would be calculating the word break for e s. Now we know that we can break
36:06:43
down this word break for E s in two parts. Either we can do like an empty
36:06:49
string and we can check for this value e s or we can do the word break for
36:06:56
the value e and we can check for the value s in this uh given word
36:07:01
dictionary. If we check if we go for this one es s es e es e es e es is not present over here. So we are left with
36:07:09
uh the second approach. In the second approach, we know that uh word break of
36:07:14
E which means this DP of one. So DP of one is already true. So we can say that
36:07:20
okay this is true. Now we only need to check that whether this S is present or not. So S directly is not present in
36:07:27
this word dictionary which means that this condition is not satisfied. This condition is not satisfied. So we can
36:07:33
say that the value for DP of 2 is actually false. So we will just mention it over here that this is false.
36:07:41
Okay, let's try to calculate the DP of three. So DP of three means word break
36:07:47
of elements ESP. Word break of ESP means three things. Uh
36:07:53
first one is that uh we need we can directly calculate to see that if ESP is
36:07:59
present or not. This is not present. So this condition won't work. Second one is we can check that whether the uh word
36:08:06
break of E is present and the word SP is present or not. And third we can check
36:08:12
is whether that word break of E S is true and uh the P is present. Now the
36:08:20
thing is we already know that this condition is not true. The ESP is not
36:08:26
present which means uh we we need to check these two conditions. Now let's
36:08:31
check this bottom condition first. So word break of ES this word break of E s
36:08:36
is actually word uh the dynam in the dynamic programming array it's the second position. So DP of 2 we need so
36:08:44
DP of two and the value P. Now we know that DP of 2 is already false which means that this condition will also be
36:08:51
false. So we don't need we don't even need to calculate and we don't even need to check for this element p in the word
36:08:57
dictionary because we know that since this dp of uh 2 is false we can just
36:09:02
ignore this case and let's focus on this one. So word break of e which means that
36:09:07
uh dp of 1. So dp of 1 is true. If dp of 1 is true which means that at least this
36:09:14
condition is true. Now we need to check that whether SP exists in the word dictionary or not and SP also exist in
36:09:20
the word dictionary which means that DP of three we can consider this as uh true.
36:09:29
Let me also put this one uh on this side.
36:09:37
Now let's calculate the DP of four which means word break of E SPN.
36:09:44
So again this will have four conditions.
36:09:51
Now I'm going to write this in a different manner. So we can also say that this is DP of 2 and PN because DP
36:10:01
of 2 represents this E S and we can also say this is DP of three and N.
36:10:10
And uh yeah these are the four conditions we need to check and if any of the them are true we need to return
36:10:15
true over here. So let's check the first one. Does ESPN exist in over here? No it
36:10:21
does not. So this is false. Uh so WB of E is true. So at least one is true but
36:10:28
SPN does not exist over here which means this is also false. Now DP of 2 this is
36:10:33
already false which means we don't even need to calculate and check for this PN. Now the last one is DP of 3. DP of three
36:10:40
is uh true. So this is good. Now we need to check whether n exist over here or not. So n exist over here which means
36:10:47
this is true. So we find one case that is true. So which means that over here
36:10:53
we can mark this value as true. And remember that uh this given string this
36:10:59
is of length four. So because this is of length four we simply need to return whatever value we find as dp of four.
36:11:08
And that is true. So in this scenario we'll just return the answer as true and that would be our solution. This is a
36:11:14
very good solution because notice that we are already calculating what we need
36:11:20
so far. We are keeping track of it at every single position because we have calculated these values. We are able to
36:11:27
use it effectively and come up to the result. Let's calculate the time complexity. So we are iterating over all
36:11:34
the elements at least once. So that is an n. Then we are also creating substrings.
36:11:43
So for every value n there can be n minus one substrings which means that we
36:11:48
need to do additional n work. So the time complexity would be of n cubed. So
36:11:55
this is also pretty high time complexity. But if you compare it with 2 to the^ of n this is actually way lesser
36:12:03
uh because this time complexity that can still be complic uh calculated and uh
36:12:09
this is a polomial time complexity but the thing is this one is exponential and
36:12:14
uh yeah we don't we we need exponential salary but not exponential time
36:12:20
complexity. So let's uh code up the solution.
36:12:27
Okay, let's create a boolean array uh to store our cache
36:12:32
and we'll name it as DP. We'll assign its length to s.length +
36:12:39
one and we know the base case where DP of zero would always be true.
36:12:46
Also for this word dictionary uh this is a list. So we are going to create a hash
36:12:53
set uh that will store the strings and we will store this word dictionary over
36:13:00
there. So it becomes faster for us to access the word dictionary.
36:13:05
We'll just name it word set. Now I think we are all set to start our
36:13:10
loop. So we'll create the two loops.
36:13:16
Notice we are starting our loop from i equal to 1 because we don't need to uh
36:13:22
we already have the value for i equal to0 and we are going to start the second
36:13:28
loop from zeroth position and while j is less than i because we
36:13:35
only need to go up to i point.
36:13:42
Now inside the loop first of all we will check that whether the dynamic programming for the J value exist or not
36:13:50
and this is what I already explained in the uh solution uh explanation that if
36:13:57
this is true then only we check that whether the word set uh contains the
36:14:04
substring. So we'll use a substring method and we'll provide the parameter
36:14:10
as J and I because J is uh less than I.
36:14:16
And uh if this is true,
36:14:21
if this is true, basically we just need to assign the value of DP of I as true.
36:14:30
And uh yeah, I think I think that's it. And we don't need to do anything. Uh and
36:14:35
at the end of the loop, we can simply return the value of our u dp of
36:14:42
s.tlength length
36:14:48
and uh yeah also when we find this value DP of I is equal to true which means
36:14:55
that we can break out of this uh inner loop because there won't be other another pair that we need to calculate
36:15:01
because even at any moment if we find a single true that's sufficient for us. So
36:15:07
let's try to run this code. Okay. Uh looks like our solution is
36:15:12
working. Let's try to submit this. Yeah, our solution works. It is accepted by lead code. But notice that this solution
36:15:19
is actually pretty slow. Uh it is taking a lot of time and uh it is not as fast
36:15:25
as our other solutions. So there is one trick we can do is rather than going
36:15:30
from I uh from Jal to I, we can actually go in reverse. So we can start the
36:15:36
position of j equal to i minus one and we can see that whether j is greater
36:15:42
than or equal to zero and we will do j minus minus. That way we would be able
36:15:48
to find this uh a little bit faster. So let's try to run the code first. Yeah
36:15:53
the this works. Let's try to submit it and see the significant difference. Now
36:15:59
our solution is much faster and uh even if you see over here previously this one
36:16:04
was running in 13 mcond and this one is now runs in 4 mcond. Basically we are just eliminating uh and breaking out of
36:16:11
this inner loop faster. We are not doing anything special. So yeah this is just something to keep in mind and uh yeah I
36:16:18
hope you liked it and I will be posting this code in the comments.
36:16:34
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to create free resources that will empower
36:16:40
every single engineer in this world so that they can do better with their technical interviews. Now continuing in
36:16:46
that direction today we are going to solve a very important problem called regular expression matching. So let's
36:16:51
get started with the problem. So if we see some of the popular companies who have already asked this question, there
36:16:56
are companies like Microsoft, Amazon, Facebook, Google, Bloomberg, Adobe, Apple, Uber, Snapchat, Tesla, Goldman
36:17:03
Sachs and Airbnb. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
36:17:11
So this is a lead code hard problem and also a very well-like problem. Basically, we are given two input
36:17:17
strings. One is string S and the other one is Payton P. Now we need to implement a regular expression matching
36:17:24
function that can support a dot character and a star character inside this pattern P as well. Now we are given
36:17:31
the definition that what does a dot and a star represent? Basically a dot can represent that it can match any single
36:17:37
character and the star represents that it can match zero or more preceding
36:17:43
elements. Now first let's try to understand both of these with examples.
36:17:48
So suppose we are given a pattern p that looks like a b and dot. Now dot by
36:17:54
definition it can support any single character. Now inside our given string s
36:18:00
suppose we are given the values to be a b c. Now can we conclude these two to be
36:18:06
matching strings? The answer is yes. Why? Because for this particular dot we can consider it to be c because it can
36:18:12
match any character. Suppose if we are given an s that looks like a b x. Is it true? Yes. This is also matching with
36:18:19
this pent because for this this time for this dot we are actually considering it to be x. But if we are given s that
36:18:26
looks like a a x is this matching? No. Why? Because the second character over
36:18:32
here this is a meanwhile the second character inside our pattern is b. These two are not matching. So this is not a
36:18:38
matching sequence. Uh so basically this is what does the a dot represents. Now let's try to get see one example of what
36:18:46
does a star represent. So basically suppose we are given a pattern P that looks like this where the values are
36:18:53
again a B star. Now what does this star is uh saying by definition? The star is
36:19:00
saying that it can match zero or more preceding elements. Now what is a
36:19:05
preceding element of this X? The preceding element is B. So which means that now this particular pattern can
36:19:13
match bunch of different uh other strings. So strings such as a b
36:19:21
does this match this particular pattern? Yes. Why? Because if we see okay first
36:19:26
character a is matching each other. Now for the second character b we can have
36:19:32
multiple bs over here because of the star value because that is what is given
36:19:37
in the definition. So based on the definition we are now in this case considering this star to be all of these
36:19:43
B's. Suppose we are given a string S that is only A. Is this matching with
36:19:48
this pattern P? Yes, this is also matching. Why? Because this star can
36:19:53
represent that we have zero or more preceding elements. So in this case we are considering that we have zero B's in
36:20:01
the pattern which means that our given S is actually matching. And in this case
36:20:07
uh since both of these are matching. Now let's try to take one more example. Suppose give our given s is equal to
36:20:12
like a bx is this matching? No this is not matching. Why this is not matching?
36:20:18
Because this ab portion this is matching. That is good. But we do not have an x over here. And uh that is why
36:20:25
this is not a match. Does this match? And uh pause the video for a second. Try
36:20:32
to guess that whether this matches or not. Let me come up with the answer. The answer in this case is that this is
36:20:39
actually a match. Believe it or not, this is a match. Why this is a match?
36:20:44
Well, okay. First f is matching. This is good up until this point. Now, because
36:20:50
we have a star with dot, which means we can have n number of occurrences of dot
36:20:55
and we know by definition that dot can represent any single character. So in
36:21:00
this case what we are going to have is we are actually going to have seven different dots and these seven different
36:21:06
dots they are going to represent each character that is missing in the remaining string and then eventually
36:21:13
when we reach to the end we are going to declare this as a match and we will be able to return true in each of the
36:21:18
cases. So I hope after so many examples things would make sense and you would
36:21:25
get the idea that what this problem is asking us to do. Basically we need to return a boolean answer whether true or
36:21:31
not that whether any given two strings do they match or not match.
36:21:39
Okay. Now before we come up with the solution first let's see that what could be the different possibilities for our
36:21:46
problem and what could be the different things we can do in the solution. Now I
36:21:51
have drawn a table over here where I'm representing different like string values and patent values and we'll try
36:21:57
to see that what happens in every single scenario and what are the actions we can take. Now I have noted that there could
36:22:03
be like a C mentioned over here in this column file and uh this means that it
36:22:09
could be any character from A to Z because in the string we can only strictly have A to Z characters.
36:22:16
Meanwhile for the pattern we could have definitely C or we could also have a dot and a star. So that means different
36:22:23
things and if they are present we might have to do things a little bit differently. So first let's see the
36:22:29
first scenario. In the first scenario basically the both the values we are given is like a simple character. So for
36:22:36
S and P suppose we are given the values like A B C and X Y Z. This is pretty
36:22:41
simple to match that whether the string matches the pattern or not. We simply need to judge character by character. In
36:22:48
this case we can simply see that whether they are matching or they are not matching. This is a very simple binary
36:22:54
operation. Second option we can have is the most beautiful option that whether we are given one character and we are
36:23:01
given a dot value. This is also very straightforward. If there is a dot present definitely it matches it matches
36:23:08
the character. We can simply return that there is a match for that particular character. Second scenario is that we
36:23:14
could be given bunch of different characters and we could be given like some characters at the beginning and
36:23:20
then we might be given like a dot and a star. In this possibility basically what
36:23:26
we need to check is that whether like a single character like this first
36:23:31
character and whether this first character I mean this could there these could be this could represent like more
36:23:37
characters these could represent something like uh a a a and like a a a
36:23:44
dot star something like that right there could be like different matching things I'm just noting down see but this means
36:23:51
that if like the the four portion matches everything at this position is
36:23:58
definitely going to match. So in this case if like the values before the dot
36:24:05
and star matches then everything is a match right if we take a look at this
36:24:11
example basically we are simply given dot and star in this case 100% there is going to be a match why because all the
36:24:18
values that are present over here we can take like 0 1 or bunch of different dots
36:24:23
and the all of these dots can represent uh all the characters that we have. Now
36:24:29
comes the interesting part where we are dealing with a star. What could be different possibilities? So let me give
36:24:36
you like one possibility. Suppose for this our string and p value we are given the values like a b and over here we are
36:24:44
given the values as a b star. Question is is this a match? Yes, this is a
36:24:50
match. Why? Because this is the first value. This is a match in itself. And
36:24:55
over here we only have one value of B. Now over here we have B star. So this B
36:25:01
star could represent that we don't have any values or we have one value of B or
36:25:07
we have two values of B or we have infinite values of B all across like the board whatever we want to choose. So in
36:25:14
this case we are definitely going to choose one value of B which means this is a match. So in this case what are we
36:25:21
considering value before the like preceding value of star. So
36:25:29
value before preceding value of star. If that is a match definitely we can find a
36:25:35
match right? There could be another possibility. We could be given a string. We could be given a p. We could be given
36:25:42
bunch of different values like a b xyz a b xyz. So far everything is the match
36:25:49
over here and then over here we are given something like uh 2 3 4 5 Z's
36:25:55
right and over here we are given like just a star value in this case how would you define that whether this is a match
36:26:01
or not well definitely this is a match but the way you are going to define is that the values that this zed and star
36:26:09
that we are considering like these values before that we are checking that whether all the values that are present
36:26:15
before that are they a match match. If all of these values are match definitely
36:26:22
uh we can create this to be a match. So again we are considering like all the
36:26:27
values before the preceding value of star. I know I'm using lot of
36:26:33
abbreviations but you just have to be with me. I'm not going to write all of them. And if that is a match, we can
36:26:38
consider this to be a match. There is also one more possibility where we actually do not need to consider this
36:26:45
like preceding value at all. What could be a scenario? Suppose we are given string s is equal to like a b c d and
36:26:53
over here we are given some p is equal to a y star
36:27:00
and then b c d. In this scenario this is definitely a match. Why? Because for
36:27:05
this yar we are considering this to be zero. If this is being considered as zero values which means that this is a
36:27:13
match and then all the other values they are match. So we will find a potential
36:27:18
match over here. So again we are considering like if the value before the
36:27:25
preceding star if that is a match then we can consider this to be a match. So now we are just like dealing with lot of
36:27:32
possibilities where every single time for value inside the pattern we will have to keep track of the value like
36:27:40
true value before that that whether that is a match or not and in order to calculate any single calculation we are
36:27:48
always checking that whether the values before us are they matching or not. So
36:27:53
this is a very good candidate for a dynamic programming solution. Why a
36:27:58
dynamic programming solution? Because first scenario we are definitely like
36:28:04
using whatever the results we have calculated to check that whether the current result we are at if that is a
36:28:09
good or not. Second already calculated results are going to give us the ability
36:28:15
to decide that what what do we do in the current position because we are not only dealing with like simple characters we
36:28:21
are also dealing with like a dot and we are also dealing with a star. So this is going to be really helpful and we can
36:28:29
use something like recursion to solve this problem but that is going to complicate things. We are actually going to use recursion with DP and that is
36:28:36
going to make things much more easier. So let's try to take one example over here and the question is for a dynamic
36:28:43
programming we are not only going because we are dealing with two different like string and pattern it
36:28:49
would be better to create a 2D matrix and inside the 2D matrix for every
36:28:54
single like uh string and every single pattern we will try to see that whether
36:28:59
the characters match or not and based on that true and false values we would be able to calculate some interesting
36:29:05
results. So let's see that in action with an example and that would make things more clear.
36:29:16
Okay. So currently we have created an example for a string and a pattern and
36:29:22
we need to check that whether they match or not. Now also for this pattern I have created a 2x2 matrix where inside every
36:29:31
single row represents the string value we have and every single column represents a character inside the
36:29:37
pattern we have and we will try to see that whether there is a match or not. Now remember the for the first row and
36:29:44
column I have kept it as empty. Why? Because uh these we are going to use to
36:29:49
create our base case. Now our base case is that currently for the string the
36:29:55
first character we have is empty character and also for the pattern the first character we have is empty
36:30:00
character. Now because these two are empty characters definitely empty characters are going to match for sure.
36:30:06
So in this case this value is always going to be true. Now we will try to see that whether there is a match over here
36:30:13
or not. So in this case because this is an empty character and we have some character over here there is not going
36:30:20
to be a match. So definitely we would always be able to like have all these values as false. So currently we are at
36:30:28
this first position this value is f this value is f both of them are characters both are same and when both are same we
36:30:35
will also have to check that all the values before that if they are also match or not. So currently the only
36:30:41
values before that were two empty strings and that represents this diagonal corner. So because this
36:30:48
diagonal corner was true and we have matching set of characters we are going
36:30:54
to take the value that is diagonally present and put it at this position for
36:30:59
this one one box. Again I'm repeating myself that because these two characters
36:31:04
are same. So first we check okay these two characters are same then we check its diagonal value because what this
36:31:10
diagonal value is going to do is it is going to check that whether all the values before these two values are they
36:31:16
a match or not and this will come in handy when we are at some position like this because if over here we find this a
36:31:23
a to be matching which means this value is a true but do we need to keep it as
36:31:29
true because if this is false which means if we are say for an example we have string to be fa and we have pattern
36:31:35
to be PA. So in this case though these two match but this is not a match. Why?
36:31:41
Because this F and P does not match. So we can break out immediately and that is
36:31:46
what we need to keep track of every single time. Then that is why this is a dynamic programming problem. So in this
36:31:52
case as explained this is going to be true. Okay. Now again let's start
36:31:57
filling up this all of these files and uh what we are going to do is okay this
36:32:03
one is true. Now we will have to check that okay currently we have fa and the
36:32:10
value we are comparing it against is f is this a match? No this is not a match.
36:32:15
So this is going to be false again. Currently the value is f a star
36:32:20
and the only value we have is f. Is this a match? Yes this is a match. Why?
36:32:26
Because for this a star we can actually consider this to be an empty string or zero values of a. And if we do that then
36:32:35
we will have no values over here. So in this case this f and this f is match.
36:32:40
And why this happened? Because we had a star value over here and we were get we were dealing with the star value. So now
36:32:48
again the new theorem comes that whenever we are dealing with a star value we will have to check the value
36:32:56
before its preceding value. Again whenever we are dealing with a star value we will have to check the value
36:33:02
before its preceding value and if that is true then we can directly mark true
36:33:08
over here. So we check okay this was true. So definitely we are going to put true over here. Awesome. Now we are at
36:33:16
this position number n. Now currently what is the scenario we are comparing? We are comparing the values of f a* n
36:33:25
and we are comparing it with f. So n and f there is no match. So definitely we can mark false over here. Now we add a
36:33:32
dot over here. Again there is a no match. So we can mark false over here. And same way this is also going to be
36:33:38
false. Okay. Now we are at this position. So now we actually have two
36:33:43
values FA. Now for this FA, if we only compare it
36:33:49
with this value F, is this a match? No, this is not a match. So we can mark
36:33:55
false over here. Okay. Now after marking false over here, uh currently we add
36:34:01
this positions. Okay. So F A FA definitely there is a match. So because these a a matches we will compare its
36:34:10
diagonal value and the diagonal value we get this result and we will mark the value over here. So this is going to be
36:34:16
true. Awesome. Now currently we are at this FA star. So FA star is this a match
36:34:22
with this FA again? Now we have the star value. So we will have to check first
36:34:28
thing we will have to check is whether we can consider this to be just like an F and empty string or we can consider
36:34:36
this to be an FA or we can consider this to be an F AAA I'm talking about this value right and if we see this F A FA is
36:34:44
all is a perfect match so now because we have a star value again over here we are
36:34:50
going to mark this as true but this true we are getting it from the value before
36:34:58
because remember in this case you must be wondering that hey for this particular position the this value is
36:35:04
actually empty then why are we marking this to be true we are marking this to be true because this one is true because
36:35:12
we found a match of f a fa and because this value is true we will mark this as
36:35:18
true so let's do that awesome now currently the next value we have is like
36:35:24
f A N and this value we have is F A. So
36:35:29
definitely there is no match. We will mark this as false and all of if we add dot we will again mark this as false and
36:35:36
blah blah blah. Right? These are all the values going to be false. Now currently we are at the position of
36:35:43
F AA. Let me clean this up a bit. So currently we have F A over here and
36:35:51
currently we only have F over here. So definitely this is going to be false. Again this FA is also going to be false.
36:35:59
Now again we are at the critical juncture. We have a star value. Now because we have a star value you must be
36:36:05
wondering that what will be the possibility. Well the possibility is again over here for this F A star we can
36:36:12
consider it to be like only F or F A or F A. This case we are going to consider
36:36:17
it to be F A. Now you must be asking that hey previously when we were at this
36:36:23
position you mentioned that uh because this is true we are marking this to be true. Then when we were at this position
36:36:31
you mentioned that though this was false but because this was true we were
36:36:36
marking this to be true. Now we are at this position this is also true. Uh
36:36:42
sorry this is also false this is also false. Then how come we are marking this as true? We are marking this as true
36:36:49
because this value is true. Mind blown. Yes, this is like the most important
36:36:56
point for this problem that whenever there is a star present, we will have to
36:37:01
check three different values. So whenever there is a star present, we were checking that whether the value
36:37:09
before the preceding value. If that is true, we can mark this as true. If there is a star present, we will
36:37:15
check that whether the value before this, if that is true, then also we can mark it true. And if there is a star
36:37:22
present, we can check that whether the value above it, if that is true, then also we can mark it as true. Which means
36:37:30
whenever we were at this position if we don't want to get into all of these
36:37:36
these like calculations all we need to do is that currently we are at this box
36:37:41
then we will have to check three different boxes. First box is the right
36:37:46
like before box. Second box is this one like the box before box and third box is
36:37:53
a box above that box. So for that this particular box if either this this or
36:37:59
this if any one of the value is true we will need to mark that value over here.
36:38:04
If all three are false then only we will mark it as false. And why this happens because this was a star value and there
36:38:10
could be bunch of different possibilities we can use over here. And this was the most difficult part of this
36:38:16
problem. And congratulations you understood it perfectly. And now because this was true now
36:38:23
currently we have this f aa and now we have this like f
36:38:28
now we are at the next value. So next value is f a* n and this n is not a
36:38:34
match. So this is going to be false and then all the subsequent values are also going to be the false. Now this is a
36:38:41
very easy problem to tackle because now we are at this position n. So this is not a match. So this is going to be
36:38:47
false. This is also going to be false. This is also going to be false. And now we are at this n and n because these
36:38:53
both of these are characters. So there is a match. Because there is a match we are going to consider it's like diagonal
36:38:59
value. So diagonal value is true. So this is also going to be true. Now this is a dot value and we only have values
36:39:05
up until this point. So which means we are going to mark this one as false and we are also going to mark this one as false. Now again we are at this value
36:39:11
number G. So we all of these are going to be false up until this point. Now there is a dot over here and there is a
36:39:18
G over here which means there is a match. So if there is a match we are going to compare its diagonal value. The
36:39:23
diagonal value is T. So that is true. So because this one is true we this is also going to be true and the last value is
36:39:29
going to be false because we only have value up until G up till this point and we have this M over here. Now the last
36:39:35
value is okay this is going to be false false and this is also going to be false. Now
36:39:40
we are at this last position. This M is a match with this M. So because this is a match we are going to take its
36:39:46
diagonal value and the diagonal value in this case is true. So we are going to take this value as true. Now our dynamic
36:39:53
programming table is complete and all we need to do is we need to check this diagonal file and we need to check this
36:40:01
last value because this last value was true. We can return true in this case and this would be the answer we need to
36:40:07
return and that is the whole logic behind this problem and uh this was a
36:40:12
very beautiful problem. If we were only dealing with the dot values this would be much easy to solve but because we
36:40:19
were also dealing with the star value it added a layer of complexity. Now if we see time complexity in this case the
36:40:25
time complexity is actually going to be big of m cross n where m is the length
36:40:30
of a string and n is the length of the uh pattern and if we see space
36:40:36
complexity because we are creating a 2x2 matrix basically the space complexity is also going to be big of m cross n and
36:40:43
this is a beautiful solution like one of the best dynamic programming solutions I have seen so far so I hope you would
36:40:50
have enjoyed it now let's move on to the coding
36:40:56
First we will check for an edge case that if both the values are null we can simply return null. If that is not the
36:41:02
case we are going to initialize our uh dynamic programming 2D array. And for
36:41:08
this 2D array let's name it as DP. And we are going to assign the length of whatever the length of s + one and also
36:41:15
length of p + 1. And we are going to assign the base value of the 0 0 to be
36:41:21
true. Okay, now let's populate the first row. So this should take care of the first
36:41:27
column. Now let's start our uh loop. So we are going to iterate over i and j which means uh we are going to do two
36:41:35
for loops. Inside the loop we are going to check for all three different par possibilities. So first possibility is
36:41:42
that uh the given characters uh the p is actually a dot. If that is the case,
36:41:48
which means it would be able to match any single character. We are marking like the DP of I + 1 and J + 1 to its
36:41:56
diagonal value. Now you must be wondering why am I dealing with like I + 1 and J + 1 because for the first row
36:42:02
and first column remember we mark their values as zero and we actually started the value of S and P on the first
36:42:09
position. So that is why every single time I'm going to updating like I + 1 and J + 1 values because the I and J
36:42:16
value is actually located at like 000 position. They have they don't have any values. So if there is a dot present we
36:42:24
simply check the diagonal value. Now the second possibility is that both of them are characters and if both are
36:42:30
characters and we they both match we can also mark their value as same as their
36:42:35
diagonal value. Now we are at the third possibility and the third possibility is
36:42:41
that if the given character if that is in the pattern a star if that is a star
36:42:47
then we will have to do some additional calculations. So now for first we are at the value star. So there could be two
36:42:54
possibility we could have some value as like character and a star or we could have some value as like a dot and a
36:42:59
star. So if if there is a dot and a star we only need to check that whether all the values before that if they are match
36:43:06
or not and if that is the case we would be good we can mark it as true and uh so
36:43:11
first let's take care of the scenario that if the given value is actually a dot star
36:43:16
now we have done that check and then we will check all of those three boxes I
36:43:21
mentioned that if either one of them is true we will simply add that value over here
36:43:28
with this uh this value we are actually comparing all of those three boxes. So if any one of them is true we can mark
36:43:34
it as true and in the end this concludes all the possibilities we can do inside
36:43:39
our loop. So basically we are done with our calculation. Now simply in the end we need to return that what was the last
36:43:46
value inside our uh dynamic programming diagonal. That should be it. Let's try to run this code.
36:43:54
Okay seems like our solution is working as expected. Let's try to run this code.
36:44:01
And our code runs pretty fast compared to a lot of other solutions and which is really good in it's great in terms of
36:44:08
time complexity and also in terms of space complexity and I will be posting this solution in the comments so you can
36:44:13
check it out from there. Thank
36:44:25
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better
36:44:30
at technical interviews. Keeping with that goal in mind, today we are going to solve a very interesting lead code
36:44:35
problem called race car. And if we see this has been one of the most popular problem at Google. Though not many
36:44:42
companies have asked this but uh the companies that did they are really popular companies. So Google, Amazon and Microsoft they all have asked this
36:44:49
question and Google literally loves this question. So let's start understanding the problem statement.
36:44:57
So this is a lead code hard problem and quite justifiably this is a hard problem. Basically we are given a car
36:45:04
that is currently located at position number zero and the initial speed it has is + one. Now we are dealing with two
36:45:11
factors here. First factor is that we have the ability to accelerate the car and second factor is that we have the
36:45:17
ability to hit the reverse button or reverse instruction in the car. And we are told that car can go infinitely in a
36:45:24
number line and car can go in like positive direction or negative direction and basically it follows whatever the
36:45:32
instructions we are providing. So what does these accelerate and reverse instruction means? Basically whenever we
36:45:38
hit the accelerate instruction car is going to change its position. So car is
36:45:43
going to change its position based on whatever speed it had previously and
36:45:48
then its speed is going to double. So what it means I'll explain it to you
36:45:54
just in a second. Also uh if if we see the instructions for uh the reverse
36:45:59
button basically whenever we hit the reverse button uh whatever the speed of our car was if it was positive speed or
36:46:07
if it was going in the positive direction basically the speed is going to turn to negative 1 or if it was going
36:46:14
in the negative direction the speed is going to turn to positive one. So basically car is going to change its
36:46:20
direction and also speed will come back to one but the car's position is going
36:46:25
to remain same which means car will only move when we hit the accelerate button
36:46:31
but this reverse button is there to dictate that which direction the car moves into.
36:46:39
Okay. So now I have drawn a numbers line over here and now we will see that based
36:46:45
on different instruction how does our car proceed and what are the different changes it happens. Uh so we have few
36:46:52
factors that we need to consider in this case. Uh first factor is instructions that we are providing. Second one is
36:46:58
what is the current position? What is the speed and what direction the car is going into? So let's start with this
36:47:04
one. Let's start filling up with the initial positions. So initially car is located at position zero and initial
36:47:11
speed is one. These are the two factors that we are given by default. Now as for the instructions suppose we provide the
36:47:18
instructions to accelerate car. What would happen is initially car was located at position number zero which
36:47:24
was this one. Right? So previously car was here now we provided the instructions to accelerate. And also one
36:47:30
more thing I forgot to mention the direction currently we are going in the positive direction because the speed is
36:47:35
positive. Now uh the position is going to become position speed plus speed. So 0 + 1 it's going to become 1. And speed
36:47:43
is also going to update to multiply by two. So now this is the new position of
36:47:48
the car. And the speed is two. But that will come in effect when we provide the
36:47:54
next instructions for the acceleration. So let's do that. If we add one more instructions for acceleration, what is
36:48:00
going to happen is that okay, currently the position was one. But now we are providing the uh accelerate in
36:48:07
instruction. So basically it's going to be 1 + 2. So now position is going to become three. So currently our car ends
36:48:13
up at position number three and the speed is going to become four because speed multiplies by two every single
36:48:20
time. If we add one more instructions for accelerate, basically our car is going to end up at 3 + 4. It is going to
36:48:28
be seven. So let's just clean this up a bit. So now the position becomes seven,
36:48:33
our speed becomes 8 and car's position is seven currently. So this is what
36:48:39
happened after three instructions that we provided that initially our car was at position zero then it came to one
36:48:45
then three and then seven. But notice all of these are just uh accelerate instructions that we have provided.
36:48:51
Let's try providing a reverse instructions. If we provide a reverse instruction, basically
36:48:57
currently the speed is + 8. So this is a positive speed. We are told that if the
36:49:03
speed is positive, speed is going to turn negative. So this is going to become minus one. Which means that
36:49:08
direction that previously we were going in the right side of direction. Now we are going in the left side of the
36:49:13
direction. We are going to proceed negatively. Remember car's position is not going to change because that is what
36:49:20
we are told that the definition of this instruction write is. So now currently
36:49:25
car is still located at this position number seven. Now let's try to put one
36:49:30
accelerate. If we put one accelerate what is going to happen? Well position is going to change. Position is going to
36:49:36
become 7 plus whatever the speed is. And speed in this case is -1. So 7 + - 1 is
36:49:42
going to become 6. Which means that now the position of car is going to end up at this position number six and speed is
36:49:49
also going to double. So now speed was minus 1. So speed would be minus2. Let's add one more accelerate. If we add one
36:49:55
more accelerate basically if this is what this is going to do is that current position is 6. So 6 + -2. This is going
36:50:03
to end up at position number four. So now car ends up at position number four and the speed will become -4 for the
36:50:12
next iteration. Say for example we decide to add one more reverse over here. If we add one more reverse
36:50:17
basically nothing is going to change in the position. Position is still going to be at value number four. But the speed
36:50:25
that was originally minus negative value now it is going to become + one. So if
36:50:31
it becomes + one which means that the direction now on is going to go on the right side and this is the whole logic
36:50:38
of this uh accelerate and reverse instruction means and this is what happens on the number sequence. So after
36:50:44
understanding this let's see that what does the question is asking us to find. Basically in the question we are given a
36:50:50
target value and we are told that we are initially starting at the position number zero and with the speed one. So
36:50:58
we need to see that what is the shortest sequence of instructions that we can
36:51:04
provide that will get us there and we need to return the length of those instructions. So let's try to see what
36:51:10
does this mean uh and see couple of examples that what this is asking us to do. Let me so I made some changes and we
36:51:18
also added one parameter target that we need to consider. So say for an example suppose we are given the target value to
36:51:24
be three. So we need to reach at the position number three inside our uh linear dis distance that we are given.
36:51:31
So let's see that what is going to be the shortest set of instructions. So if we provide an one accelerate which means
36:51:37
position is going to become 0 + 1 it's going to become one. Now speed is going to become two for the next step and our
36:51:45
car is going to end up over here. Now let's add one more accelerate. If we add one more accelerate basically our
36:51:51
original position was 1. So 1 + 2 it's going to become three. This three is critical because this is what the target
36:51:57
is asking us to find. So we have already reached the target value. And uh speed like it's going to become four. But this
36:52:04
is not going to be of concern because we already hit our target value. So since we hit our target value and this is the
36:52:10
shortest possible way to do it. It took us two instructions to reach to the target value three. So in this case as
36:52:17
the answer we are going to return two that we need minimum of two instructions to reach to the target value of three.
36:52:24
Say for an example we take one more uh consideration. So in this case we provide the first instructions of a. So
36:52:30
in this case our position is going to become one. Our speed is going to become two. Our car is going to end up over
36:52:36
here. We add one more accelerate. In this case our car is going to end up over here. Our position is going to
36:52:42
become three. And our speed is going to become four. Let's put one more a. So our car is going to end up over here and
36:52:50
we are going to the position is going to be seven. The speed is going to be eight. The thing is we were we we were
36:52:57
intending to reach to this position number six. But this seven is actually greater than six. Which means we have
36:53:03
already surpassed that. So we need to come back which means we will have to change the direction. So previously the
36:53:08
direction we were going is in the right side direction. We will have to change the direction. Whenever we have to change the direction we are going to use
36:53:14
a reverse. If we use the reverse pos car's position is not going to change but speed is going to become negative 1.
36:53:20
Now the because the speed is negative 1. Let's try to add one more accelerate. If we add one more accelerate basically the
36:53:27
position is going to become 7 + -1. So it's going to become 6 and our car is
36:53:32
going to end up at value number six. Now the speed is going to become -2 for the next iteration but we don't care. And in
36:53:39
this case the target value six has been achieved. If we see how many instructions it took, it took us five
36:53:44
instructions to get there. So in the answer we are going to return five that we need minimum five instructions to
36:53:50
reach to target value number six. And this is what the problem is asking us to solve. Now let's see that what are going
36:53:56
to be the different approaches to solve this problem. Well, there are actually two ways to solve this problem. First
36:54:01
way is to treat like every single value as nodes and use like a breath first search to solve this problem and
36:54:07
treating this as a graph problem. The other way to solve this problem is treating this as a dynamic programming
36:54:13
problem and Google is actually huge in dynamic programming concern like they
36:54:19
really love their dynamic programming concepts and uh this is what I'm going to show you in this approach. So let me
36:54:25
know in the comments if you want to see the BFS solution as well. I can show it to you maybe sometime in the future.
36:54:34
So before we come up with the optimal solution first let's try to understand that what are the moves of accelerate
36:54:40
and how it works for every single instructions. Suppose okay initial position is going to be zero and initial
36:54:46
speed is going to be one. We all know that if we add one instruction of a okay our car is going to end up over here.
36:54:52
This was the first position right? If we add one more instruction of a our car is going to end up over here. If we add one
36:54:59
more instruction of A, our car is going to end up at position number seven. And if we add one more instruction of A, our
36:55:04
car is going to end up at position number 15. Why this happens? Because speed gets multiplied by two with every
36:55:11
single occurrence of A and that is where we are doing like position addition. Right? So is there a mathematical sense
36:55:19
behind these values? And yes, there is. How can we define that? Suppose we
36:55:25
define a parameter called x that refers to the number of accelerations we use.
36:55:33
So in this case uh currently we have used four accelerations. So currently x is going to be four. Right? We are just
36:55:40
using some arbitrary variable to define a mathematical equation. Now in this case if we directly want to know that
36:55:48
what is going to be the position based on the number of x can we directly know it? Yes. The equation is if we do 2 to
36:55:55
the^ of x minus 1 then it will provide us that for any number of accelerations
36:56:02
what is going to be the position of the car and this is a really important thing to find. Now how can we define this
36:56:09
theorem? So say for an example if we are originally given only with two a so two
36:56:15
times we are using uh this. So currently x is equal to two. We know that when we
36:56:20
provide two accelerations the value we have is car is going to be position number three. If we apply this formula
36:56:27
basically it's going to be 2 to the^ of 2 - 1. So 4 - 1 is going to be 3 which is correct. Same way if we try to apply
36:56:33
x to be 4 in this case the answer is going to be 2 to the^ of 4 - 1 which is
36:56:39
going to be 16 - 1 which is 15 and which is what we calculated. And why this is
36:56:44
happening? Because every single time speed is being multiplied by two. So we
36:56:50
are we can actually see a relationship forming between the position of car by
36:56:57
the value of a. And the important thing is a is only being used to move the car.
36:57:04
So car can move in this direction or this direction that depends on the value of r. But the thing is car is only going
36:57:11
to move based on the value of a. Okay. Now after knowing that what are going to be different possibilities of a there
36:57:18
can be three distinct possibilities of for us to find the target value. Suppose the target value we are given it is
36:57:25
located someplace like this. Right now there can be three distinct possibilities and currently we are only
36:57:31
considering that we are only using accelerate function. We are not using reverse function for now. When we use it
36:57:37
I'll let you know. The first possibility is that we find some arbitrary value of accelerate that gets us somewhere over
36:57:44
here. Which means we are not at target value but we are one value before that
36:57:49
that can like as further as we can get near the target value using only accelerate. Another possibility is that
36:57:56
if we do one more accelerate we go beyond the target value and we reach somewhere in this area.
36:58:04
Now the third possibility is that if we only use accelerate function, we directly hit the target value. If this
36:58:10
is the case, this is going to be like the minimum number of effort we need to find the answer. And this is going to be
36:58:16
the best case scenario, but that rarely happens. There can be infinite numbers and there are only so many numbers that
36:58:22
can directly hit a. So now let's see that what would happen in each of these scenarios where either we are located
36:58:30
before the target value or we are at after target value. What should be our
36:58:35
approach in each scenario right? So let's try to understand this logic with
36:58:41
something important uh concepts. First concept is that say for an example we
36:58:47
are in a scenario where our position is somewhere over here and this is the
36:58:52
target value and if we do one more direct acceleration we are jumping away. So other logic is that we already know
36:59:00
how much effort it took to get here right we have already those sets of instructions so we we won't bother doing
36:59:07
anything but now from this point we can actually break down the problem in a
36:59:12
smaller sub problem where we only need to check that how much effort it takes
36:59:17
to make these moves and we can actually do that why because at this position
36:59:24
whatever the speed is say for an example speed is eight If we use a reverse in this case, speed
36:59:29
is directly going to be minus one. Which means we have the ability to go like on
36:59:36
this direction and it could be beneficial to go in this direction for a bit and then come back directly towards
36:59:42
the target direction because we already have the equation that position is going to be 2 ^ of x - 1 and using this we can
36:59:51
do some pretty cool results. Right now in this case if we slow down over here
36:59:57
if we use a right uh over here which means immediately we have two
37:00:03
possibilities either we can use accelerate and go in this direction or from here we can directly use one more
37:00:10
reverse and then directly go to this T because if we slow down here we
37:00:16
definitely would have to use two different Rs because first R is going to make the direction go negative and
37:00:22
second R is going to make the direction go positive and then we would be able to reach to this target value. That is one
37:00:28
logic. Second logic is suppose we are in opposite scenario where the target value
37:00:33
we we are given it is located here and the answer we are trying to find or based on the accelerates we did we end
37:00:40
up somewhere over here. So if we have already gone beyond the target value the
37:00:45
basic logic is that we definitely will have to use the reverse gear and after
37:00:52
using the reverse gear our speed is going to go in that direction. We only need to be concerned about finding this
37:00:59
smaller path rather than finding the whole path. So we are only finding the
37:01:05
difference between say for example this is the target value and this value we call it like I value. So we are only
37:01:11
considering to finding that how many moves it takes for us to do like I minus T target value and this is a smaller sub
37:01:19
problem and same way in this scenario suppose this is value I and this is
37:01:25
value T. So in this case we are finding a smaller sub problem T minus I to find
37:01:30
that how many moves it takes to do this and we keep on breaking this again and
37:01:36
again and again if until the point where we reach to a target position and using
37:01:41
acceleration we get to the same value and then we mark its moves. So this is the whole logic of the solution we are
37:01:48
going to use and for every single position there can be different like uh options we can take but basically this
37:01:55
is how we are breaking up bigger problem and grinding down in the smaller sub
37:02:00
problems to find the answer that we need. So basically we are using dynamic programming at its finest.
37:02:09
So let's see that some with some of the examples how we can actually solve this problem and at the same time we are also
37:02:17
going to use some logic to our advantage. The logic we are going to use is that we are going to initialize a DP
37:02:23
array. Now inside this DP array we are actually going to mark the positions of
37:02:29
accelerations using the formula we already established that is 2 2 to the^ of x - 1. And over here we are going to
37:02:36
mention the index values as the number of a's or the number of x in this case
37:02:43
and we are going to see that what is the what position does it ends up at. So if
37:02:48
this is zero this is definitely zero. Then for the pos this is one this is
37:02:54
going to be three and this is going to be seven and this is going to be 15. Right? These are the different possibilities we have. I have already
37:03:00
drawn a number series over here as well. Now say for an example the target value we are given the target value is value
37:03:08
number seven. If the target value is value number seven do we need to do any calculations? No. Right? Because we can
37:03:14
directly see over here that this provides us the value of uh seven then basically it takes us three steps to
37:03:22
reach to the value target number seven. So in the answer we can directly return seven as the answer. And why we were
37:03:28
able to do it? Because we only use acceleration to get there. So this is
37:03:34
like the best case scenario. This is one of the examples. Say for an example, the given problem is not so simple. Suppose
37:03:40
the given target we have is value number 9. What we are going to do in this case? Now things becomes a little bit tricky,
37:03:47
right? We are trying to reach this target value. We already have our uh
37:03:54
this DP array. So based on this we already know that target falls between these two values. So it has to be
37:04:01
playing around between these two numbers right. So let's mark both of them down. So first this is the first position that
37:04:08
we can reach and it took takes us three steps to get there. So we already know that there is an effort of three steps
37:04:15
to get to the value number seven and our aim is to reach to the target value number nine. Right? Also there is
37:04:22
another possibility that we are we can end up at value number 15. And it takes us like four steps to get to this value
37:04:29
number 15. So now let's just mark down all the three steps that we took to get over here. And we are also marking down
37:04:36
all the four stop steps that we get to reach to this value number 15. And now
37:04:41
we will try to break the problem into a smaller sub problem. And the smaller sub problem is that what is missing over
37:04:48
here? We need to recover these two steps. How we are going to recover these
37:04:54
two steps? The how many effort it takes us for each to two steps. If we look at
37:04:59
this DP sol uh array, we do not find a direct entry that uh can only be done
37:05:05
using only accelerate values. Right? But what we can do is at this position
37:05:11
number seven, we can add a reverse over here. If we add a reverse over here, what's going to happen is that now speed
37:05:19
at this position is going to become minus1 and currently okay. So position is 7 and speed became minus one. Right?
37:05:27
Now what are the some of the interesting things we can do? First interesting thing we can do is we can try to find
37:05:35
that if we go in this direction and we are able to calculate some direct DP
37:05:42
that we can make. Uh so say for an example if we take one step now the
37:05:47
position is going to become six the speed is going to become minus2 and over here we took 1 a and currently this is
37:05:55
the position and now what is the difference between these two entries the difference is actually three we can
37:06:02
directly make so let's see that what is going to be the effort to make this answer viable right the effort is that
37:06:09
now at this position we will have to do another reverse so If we do another reverse, the value is going to become
37:06:15
one. And now we need to move three steps. So three steps means two accelerations. So we can do two
37:06:22
accelerations. What is the cost of this one? The cost of this is 1 2 3 4 5 6 7
37:06:27
8. So in total it took us eight steps to get here. Still have one more possibility. And that possibility is
37:06:34
that we need to find the target value to be 9. And we have this 15. So let's see that how much effort it takes for us to
37:06:41
get there. Okay, now currently we are at this position number four and uh
37:06:47
currently we have four A's. Now we need to change the direction. So we hit a reverse and now the distance we need to
37:06:52
cover is six. From the previous example we already know that if we want to cover six direction basically we need five
37:07:00
steps. I'm not going to go in detail on showing all five steps but that is the
37:07:05
uh that is how many number of steps we need. So let's see that what would be the effort in this case because
37:07:10
previously the best we could find is eight. But in this case the effort is these many steps plus five steps. And
37:07:17
notice we only have to use a single r over here because once we change the direction we don't need to change the
37:07:23
direction again because it's in our favor to keep the same direction. In this case uh the answer is actually
37:07:30
going to become 10 steps. So again 8 is going to be the best number of steps we
37:07:36
can do in order to find the target uh what are the minimum values needed for
37:07:42
target value number nine and in this case we are going to mark eight as the answer. Let's do a quick recap on all
37:07:49
the things we did. So the number of things we did is okay this was the target value we choose what is the
37:07:56
minimum a that gets us and what is the next a that gets us and then we tried to
37:08:02
make this distance by comparing all the possibilities. So over here we actually went backwards and then we went
37:08:09
frontwards but we were able to do it pretty quickly because we had this DP array setup. If we see time and space
37:08:15
complexity in this case the time complexity is actually going to be big of n log n
37:08:22
and space complexity is actually going to be bigo of log n. Now why we are
37:08:28
dealing with a logarithmic time complexity because remember with every single jump we are actually jumping in 2
37:08:35
to the power of n. So we are eliminating lot of values with every single jump and
37:08:41
this is a very good time and space complexity. So I think I hope you would have liked this uh explanation. Now
37:08:47
let's move on to the coding.
37:08:54
So before we start implementing the race car function, we are actually going to create a helper method. So let's
37:09:00
initialize our recursive helper method. So after initializing our helper method,
37:09:05
we are going to check for a condition that if the given value inside the dynamic programming array if that is
37:09:11
greater than or equal to zero, we are simply going to mark it as our successful case. Uh if that is not the
37:09:18
case, we are going to assign the current value of uh DP to be the maximum value
37:09:24
possible. Now let's initialize our couple of variables. So first we are initializing our variable x and uh that
37:09:30
is going to be of the value one and we are also going to initialize a value called j and that is going to help us to
37:09:38
iterate over the smaller distance. Okay. Now we are going to run our for loop and
37:09:45
inside the for loop we are going to use uh utilize the function of uh like 2 to
37:09:50
the^ of x - 1 and basically we are going to keep updating the value of j until we
37:09:56
come to a position where we are just before uh the target value and after
37:10:01
doing that inside we are also going to initialize a for loop to find the smallest distance between the two
37:10:08
values. So all we will have to do is every single time we are going to calculate the value of DP of I and for
37:10:15
that we are going to compare that what is the minimum cost that is happening for us. So we are going to compare the
37:10:22
value of the DP of I that we have already stored or we are also going to compare the value of uh the given number
37:10:30
of steps we need to take. So number of x plus we will also have to add one more
37:10:36
value that is to take care of one reverse function and we will also have to add one more value that is to take
37:10:42
care of the another reverse function and we will also have to take care of the number of cues that we need to jump and
37:10:48
plus we will also have to call the recursive function and see how many
37:10:54
steps does that takes in order for us to get there. So over here we are going to
37:11:00
provide the value of the target minus uh the number of J minus P that we
37:11:06
received. So this is the jump that we take and we are also going to provide our DP array that we have created. And
37:11:12
basically this is the whole logic behind our solution. And once that is done
37:11:19
basically we can get out of the loop and now we can compare again the smallest result possible. So for this scenario
37:11:26
what we are going to do is uh we are actually going to again compare the two values and inside the two values. First
37:11:33
value is going to be the existing DP of I value that we have received from running this loop and second value we
37:11:41
are going to compare it. it is going to be this second scenario takes care where
37:11:47
we are actually jumping one step above the given uh values and
37:11:54
in the end we simply need to return the smallest number that we have been able to find from our main function we will
37:12:00
have to make call to this one and we will also have to initialize our DP array also going to fill the value with
37:12:07
all the negative values uh except the first one and now we are going to call our function
37:12:15
Okay, seems like our solution is working as expected. I put uh I in place of
37:12:21
target at many places. So I just fix that and uh now let's try to submit the code.
37:12:27
Okay, seems like our solution is working as expected and it is reasonably faster than lot of other solutions and uh I
37:12:34
know this was a very tough problem to understand. I hope you had a good chance to understand the explanation and also
37:12:40
go through the code couple of times. I'm going to post this in the comments and I also have my own GitHub repository where
37:12:47
I have solved like lot of different problems and I'm going to put the code here as well. So it's up to you wherever
37:12:53
you want to check the code from. Uh I hope you like the explanation.
37:13:09
So today we are going to do a full course on greedy algorithms and we are going to learn everything there is to
37:13:15
know and I can guarantee you that by the end of this course you would become a complete pro on all sorts of greedy
37:13:21
questions. You would be able to identify, understand and solve them flawlessly. So without any delay let's
37:13:27
get started with the course. So greedy algorithm is nothing but a
37:13:34
problem solving technique where you take the given problem and try to carve out
37:13:40
the biggest possible solution you can and then try to deal with the remaining portion and also again repeat the same
37:13:47
problem and even with the remaining portion of the problem you also try to carve out the biggest uh solution that
37:13:53
you can and so on and so forth. So you basically break a problem down into sub problems and then even in the sub
37:14:00
problems you also repeat the same pro same approach but at every given chance you are trying to find your best way to
37:14:08
solve the solve as much of a problem as you can. Let's try to understand this with an example. Suppose you are a
37:14:14
cashier at one of the gas station and you realize that someone comes to you with a $100 bill who only had the amount
37:14:22
that you need to charge was $67.35. Let's say that this this was their bill
37:14:28
and they hand you over $100. What is going to be your first approach? The immediate thing that would come to your
37:14:34
mind is that you need to return $22 and 65 to that person. Now if you have to
37:14:41
return $22.65 the first thing you are going to do is take out the biggest chunk by the
37:14:47
biggest denomination of money. So you are going to take a $20 bill which means now the remaining amount is going to be
37:14:53
$2.65. Once again for this one you are also going to repeat the same problem uh and
37:14:59
same approach. So you are going to take a $2 coin and yes in Canada we have $2 coins so we can use that or a $2 bill
37:15:05
and then now you only have to deal with 65 cents and for 65 cents once again you are going to take two quarters so that
37:15:12
is going to be 50 cents and now for the remaining 15 cents you can take one dime
37:15:17
so 10 cents and one uh nickel so that is 5 cents and overall with this
37:15:23
denomination you would have created basically the ideal amount of money that
37:15:28
you will have to return to that particular person and you can just hand them over. This is where you took the
37:15:35
biggest problem that is that you need to return to $22.65 65 cents and then you started breaking this down into the
37:15:42
subsequent portion of the different denominations that you could and at every given step you were being greedy
37:15:49
and you were trying to solve the most amount of problem at any given point and
37:15:55
that's the whole approach on solving greedy problem.
37:16:01
Now if you see the structure of the greedy problem it looks very similar to lot of other approaches that we have
37:16:06
seen. Number one, it seems very similar to dynamic programming approach. Second thing, it seems very similar to
37:16:12
recursive approaches that we see because we are dealing with solving sub problem within a sub problem within a sub
37:16:19
problem for different inputs. And third thing is many times you can also consider it closely related with most
37:16:25
simple brute force approach and you would be true in saying that uh greedy
37:16:30
approach looks very similar to all of these three techniques but there are slight variations and differences. First
37:16:36
let's understand that what is going to be the difference between a greedy approach and a dynamic programming
37:16:42
approach. Well, for the greedy approach, you are trying to solve the biggest
37:16:47
chunk of the problem. Uh that's it. But in the dynamic programming approach, you
37:16:52
actually take a problem and you break the problem in uh subpieces and for
37:16:59
those sub pieces you try to store their answer and based on that stored result
37:17:04
you try to build more sub pieces and then you build your solution. So if we
37:17:10
have to consider greedy approach you can treat it as if eating a cake where you have a big cake you take out a big chunk
37:17:17
of the cake. So now you are only dealing with a smaller sub portion of the cake and once again you can take out the
37:17:23
biggest chunk and now you are only dealing with even smaller sub sub portion of that cake. But meanwhile in a
37:17:31
dynamic programming you can treat it as building bunch of different Lego bricks and based on the combination of having
37:17:38
these Lego bricks you would be able to combine them together to build your solution in a particular fashion on top
37:17:45
of already computed results. So this is the visual difference between a greedy
37:17:50
approach and a dynamic programming approach. And you would see in many problems where uh you would feel like
37:17:57
hey this should be solved using greedy approach but uh eventually you would hit a hit a brick wall and you would find
37:18:03
that dynamic programming would be much better way and vice versa. So you would always be using these two tandem
37:18:09
interchangeably and you can make that judgment call that what do I need to choose greedy approach or dynamic
37:18:16
programming approach. Next thing is that what is the key
37:18:23
characteristics to understand that uh this is a good suitable candidate for a
37:18:28
greedy problem solution. Number one thing is it should have an optimal substructure. So what do I mean by
37:18:35
optimal substructure? Well, because originally you are trying to solve a
37:18:41
bigger problem and you are taking some or majority of the portion out of that
37:18:47
problem and now you are only trying to solve a smaller problem and once again repeating the same process. So so on and
37:18:53
so forth. So this is a good candidate to understand that hey can I apply greedy solution to this? Let's go back to our
37:18:59
question of the cashier who was trying to break money because originally the
37:19:05
cashier had a bigger amount that needed to be returned and then after taking a
37:19:10
big chunk out of it $20 we still had a smaller amount that would still needed to be returned and we would apply the
37:19:16
same logic on top of it. So that is number one. Number two thing is whenever you are trying to deal with maximizing
37:19:23
or benefiting from your input. So let's say that I give you an example. Let's say even in the cashier's problem, I
37:19:30
would have told you that you need to return the change in the minimum possible bills or coins and that minimum
37:19:39
word would be a key characteristics or a key phrase for you to understand that
37:19:44
hey let me try to solve this problem using greedy approach. So whenever you are trying to maximize your profit or
37:19:50
minimize the amount of re work that you have to do or there is the greatest value that you are trying to find or the
37:19:57
lowest value that you are trying to achieve some keywords like this if whenever you see something like this
37:20:03
always think that can I use greedy approach to solve this problem and more likely than not you would be able to do
37:20:09
it like if you see a very popular example we have a very famous algorithm
37:20:14
called prim's minimum spelling link algorithm and I have done a separate video on this and uh you can find it at
37:20:22
any different place but this algorithm typically uses the greedy approach where
37:20:28
if you are trying to traverse between any two particular node at any given moment all you need to do is you need to
37:20:34
pick the direction which leads the smallest edge weight and if you keep on
37:20:39
doing that basically you would be able to traverse the entire tree uh in the minimum spanning or min with minimum
37:20:46
cost and that's a great great example on how this very popular and very famous
37:20:52
tree and graph related algorithm can use greedy algorithm technique to basically exist. So there are many benefits of
37:21:00
using greedy algorithms and we are going to see about all everything about all of them in the top 10 lead code problems
37:21:07
that we are going to solve. So now without any delay I won't spend much time explaining the theory. I would
37:21:14
rather explain you these 10 problems and you would be able to understand that what different problems can be asked
37:21:21
what are the pattern that we are trying to recognize over here and how do they actually work so without any delay let's
37:21:28
get started with these questions now today we are going to do maximum subar
37:21:33
lead code problem and if you see some of the companies where I want to get a job who already asked this question there are companies like LinkedIn Amazon Apple
37:21:40
Microsoft Google Adobe Facebook Bloomberg, Uber, Bidance, Yahoo, eBay
37:21:46
and Splunk. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
37:21:52
So this is a lead code medium problem and very well like problem on lead code. Basically we are given an array called
37:21:58
nums and we need to find a continuous subarray which has the largest sum and
37:22:03
then return the sum value. We are also told that a subarray is a continuous part of any array. So we are given the
37:22:09
definition of it. Now let's try to understand this with an example. So suppose this is the example we are given. Well, I have actually drawn this
37:22:15
example uh in much bigger format over here. So for this example what we are going to do is we are going to see
37:22:21
different sub areas and then we are going to see that what is the maximum sum we have we are able to find so far
37:22:27
and then in the end we'll return whatever the maximum sum you have found. So first of all this value is actually -2. So because this value is -2 even if
37:22:35
all the remaining values they are positive it makes no sense for us to keep this value. So we are going to ignore this value and we are not going
37:22:40
to keep it in our current subarray. Now this value is positive 1. So that is good. But again combination of these two
37:22:47
is actually minus2. So again we cannot keep this in the our continuous subarray. Well now this value is
37:22:54
actually positive4 and which is good sign. Now these two value this is again still positive 3 which is also a good
37:22:59
sign and the combination of these three is again five and then we add this value. So this becomes six and we are
37:23:06
going to keep on updating the max value as well. So max value so far we have found so far is six that we can say that
37:23:11
up until this point the sub area there where we have found the maximum value to be is six. Now this is again minus 5. So
37:23:19
the if we do 6 + - 5 we still get positive 1 value which is again positive. So we are keeping this as a
37:23:24
sub array and then again this value is + 4. So + 4 + 1 becomes + 5. So this is
37:23:30
also positive. But the thing is uh in the end up until this point the maximum value we were able to find is six. So
37:23:37
because it was six, we are going to return six as the answer. This is what the problem is asking us to do. We need
37:23:42
to find the sum of maximum subarray and then return that value. So let's see what would be different approaches to
37:23:48
solve this problem. Basically we need to find the maximum subarray. What we can do is we will try
37:23:54
to find every single possible subarray. Try to see the sum of all of those characters and whichever possess the
37:24:01
maximum sum we simply return that sum. So let's see that in action. So first of all what we are going to do is we are
37:24:06
going to take some of this character. Then we are going to take some of these two characters. Then we are going to take some of these three characters and
37:24:12
so on and so forth. We are keep on repeating the process with this first element. After we are done with this
37:24:18
essentially we are going to get rid of this first element. And now whatever the remaining elements are we are going to
37:24:24
start taking some of those values. So in this case what again we are going to do is we'll take this element. Then again
37:24:30
we will take these two elements and again we will take these three elements. And overall we will keep on making the sum and eventually we would find the
37:24:36
answer and the answer in this case is going to be the sum of these three characters and whatever the answer is we
37:24:42
can simply return that. So this approach would work as expected but the issue with this brute force solution is
37:24:48
actually that we are doing a lot of repetitive work. If we see the time complexity in this case the time complexity is actually going to be big
37:24:54
go of n². So let's see that what would be the better way to solve this. Before
37:24:59
we come up with the optimal solution, first of all, let's make couple of things very clear. Uh what is our aim and what is the thing that we are trying
37:25:05
to find? Well, basically we are trying to find that what is the maximum sum subarray. At any given moment, there can
37:25:12
be any current subarray that we are iterating over which could be the maximum subarray or could not be the
37:25:18
maximum subarray. We don't know. But at any given moment, we will have need to have the ability to keep track of sum of
37:25:24
all the characters that are present in that particular subarray. So which means that we are going to have a variable
37:25:29
called current or current subarray where we are going to keep track of the sum of all the current variables that we are we
37:25:35
have it over and we are keeping track of. Uh well second thing is that we need to find the maximum subarray and amongst
37:25:41
any of the subarrays anyone could be the maximum subarray. So we are also going to keep track of another variable called
37:25:47
maximum subarray where we are going to keep track of maximum current sum we have found so far. So well these two
37:25:54
things are understandable right? uh they are from programming perspective. But there is also one more thing that is
37:25:59
actually rational and the rational thing is that at any given moment suppose this value is actually minus3. So current sum
37:26:07
sum or current subarray we have found is actually minus3. So if this value is minus3 because this value is negative.
37:26:15
So if this value is negative even though all the remaining values they are positive and they keep on increasing the
37:26:22
value in size this minus3 is always going to have to cause them to have a
37:26:27
lesser value. So if that is the case why are we even bothering to keeping this value at our bay or at our disposal. So
37:26:35
the idea is at any given moment for our current subarray the moment we would identify that the current value or some
37:26:42
set of current values they are causing it to have a negative value. If that is the case, we are going to immediately
37:26:49
update our current subarray and then we will keep on moving towards the next values. And based on these two logics,
37:26:56
uh all we are going to do is we are going to iterate over our given array and keep on going to updating the current subarray and then keep on
37:27:03
updating the maximum subarray we have found so far and in the end we should be able to find the answer. So let's see
37:27:09
that traversal in action. Before we start iterating over this variable, we are going to define some default values
37:27:14
for this current and maximum variable. The default value for current is going to be the zero and for maximum it's going to be whatever the first element
37:27:21
of this given array is which is minus3 that is to cover an edge case where we are only given one element. Now let's
37:27:26
start iterating over. Okay. So now uh the sum of these two elements is actually going to be minus3 + 2. So -3 +
37:27:33
2 is actually going to be minus1 which is still less than 0. So because this is less than 0 we are not going to update
37:27:38
our current max variable. And the maximum sum we are actually able to find so far is going to be zero which is
37:27:44
definitely greater than minus3. Now again the for these three variables again the sum is going to be negative.
37:27:50
So we are not going to do anything and we are going to ignore all three of these cases. Now this value is actually
37:27:57
positive. So because this value is positive the current sum we have is going to be 8. So which means we'll have to update the maximum sum we we have
37:28:03
found so far to be the value 8 as well. Now again we add the sum of these two values. So 8 + -1. So 8 + - 1 actually
37:28:11
becomes 7. So this becomes 7 which is less than whatever the maximum value we
37:28:16
have found so far. So we don't need to update the max variable. Now we again add this value to our current sum. So 7
37:28:22
+ 2. 7 + 2 is 9. 9 is greater than whatever the maximum value we had. So this becomes 9. Okay. Now again this is
37:28:30
also a positive value three. So we can do 9 + 3 which becomes 12. So we are again going to add the value 12 to our
37:28:36
maximum sum that we have we have been able to find so far and then this value is actually -5. So we can do 12 + - 5.
37:28:44
So 12 + - 5 is going to be 7. And again because this value is still positive we are keeping this current subarray going
37:28:51
on because we we don't know future values might be positive values and this can also go up pretty quickly. Now uh we
37:28:58
are we have actually reached to the end of this uh array and we don't have any more elements to go over. So the maximum
37:29:04
sum we have found so far is 12 and this is what we need to return as the answer in this case. Uh and so this is the most
37:29:11
optimal approach to solve this problem. If we see time and space complexity in this case the time complexity is actually going to be big of n. Why big
37:29:18
of n? Because we'll have to iterate over every single array or every single value that is present inside this given array
37:29:24
which takes big of n time. If you see space complexity in this case the space complexity is actually big go of one or
37:29:29
constant space because apart from storing these couple of variables we are not using any additional space. So
37:29:35
that's why space complexity is very minimal.
37:29:41
First of all we are going to initialize two variable called current sum and maximum sum. For current sum we are going to initialize the value to be zero
37:29:48
and for maximum sum we are going to initialize the value to be the first value inside this given nums array. We
37:29:54
are going to create a for loop to iterate over this given array. Now we are going to check that whether the
37:30:00
current sum if that is less than zero or not. If that is less than zero, we are going to update the value of current sum
37:30:05
to zero. That is not the case. We are going to calculate the value for current sum and maximum sum. So current sum is
37:30:11
going to be current sum plus whatever the current value inside this given nums
37:30:17
array we have. And we will have to check that whether the current sum we have created if that
37:30:22
is the maximum sum or not. And after loop ends we simply have to return maximum sum. Let's try to run this code.
37:30:32
Seems like our solution is working as expected. Let's submit this code.
37:30:38
And our code runs pretty efficiently. I will be posting this in the comments so you can check it out from there. Thank you.
37:30:50
Hello friends, we are still not employed by a fang company. So let's not stop late coding till we get there. Today we are going to do jump game problem.
37:30:57
Recently this problem has been asked in Amazon, Facebook, Apple, Google, Oracle, Tik Tok, all these gigantic companies
37:31:03
and uh they are some of my dream companies. So I'm going to do my utmost focus for this video and I hope that you
37:31:10
uh find it enjoyable. This is going to be the framework for the video. First we are going to understand the problem.
37:31:15
Then we will come up with a brute force approach. We'll improve our brute force approach. We'll find the optimal
37:31:21
solution and then we'll write the Java code for the optimal solution.
37:31:26
This is a medium problem and we are given an integer array nums and we are
37:31:31
initially positioned at the first index. So zero index. Each element in the array
37:31:36
represents that the is the maximum jump we can take. And if that is true, can we
37:31:43
reach to the last position? So if we are able to reach to the last position we would uh return true. If we cannot
37:31:49
return reach we can we will return false. So let's understand this with an example. Suppose our given input is like
37:31:56
2 3 1 1 and four and initially we are located at this position. This is the
37:32:04
same example over here. So we can see that if we over here we can take maximum two jumps. So either we can take one
37:32:11
jump and reach over here or we can take two jumps and reach over here. Let's let's get the greedy approach and we'll
37:32:18
take the maximum number amount of jumps. So over here if we take two jumps we end up over here. Over here the maximum jump
37:32:24
we can take is only one. So we can we'll reach over here. Again the maximum jump we can take is just one. So we'll reach
37:32:30
over here. And this is our last position. So since we have reached over here which means that we can conclude
37:32:35
that we can uh solve this jump game and we can reach to this end position. So
37:32:42
we'll return true in this case. Now let's take uh one more example. So suppose we are given input like this 3 2
37:32:49
1 0 and four. And
37:32:54
if we check for the possibility. So over here the maximum number of jumps we can take is three jumps. So if we take three
37:33:01
jumps we reach at zero. From zero we can't move any any anywhere for forward.
37:33:06
Uh so let's rather than taking three jumps we'll try to take two jumps. So if we take two jumps we end up over here
37:33:13
and over here the maximum we can take is just one jump. So again we end up at zero. And lastly rather than taking two
37:33:19
jumps from here we'll just take one jump. So we'll end up over here at this position number two. Now at this two the
37:33:26
maximum jumps we can take is two. So again we end up at the zero which means that in any circumstances if we start at
37:33:33
this position number one we cannot reach to this last position. So over here we
37:33:38
would return false. This is basically the problem statement.
37:33:44
Uh I have given a custom example that we are at any position we are going to
37:33:50
first of all see that what is the maximum jump we can take. We'll try to make that jump. We will try to see that
37:33:57
using that jump. If we can reach to this end index. If we cannot reach to the end
37:34:03
index somehow we will backtrack. We will go back to the position where we
37:34:08
initially took the jump from and we will try some other possibilities. So let's
37:34:13
see that in action. So over here we are initially at this position number
37:34:19
two. The maximum jump we can take is at value number two. So that jump will
37:34:24
bring us over here. Now over here the maximum jump we can take is at uh this
37:34:30
position zero which means that we can't move any further. So we will backtrack.
37:34:36
So we will backtrack. We will come back over here. Now again we are at the second position.
37:34:43
Now let's rather than taking the two jump we will reduce our jumping
37:34:48
possibility and we will just take jump of one step. So now we reach at this value number three and over here with
37:34:55
this value number three we can take maximum jump of three steps which means that we can if we take three steps we
37:35:02
will end up over here. So 1 2 3 and at this position two the maximum number of
37:35:09
steps we can take is two which means that even if we take two steps we will cross our last entry which means that in
37:35:17
any case we would be able to reach to this last element and we would return true in this scenario. Now this approach
37:35:25
seems sensible on pen and paper because we are dealing with a small number of uh
37:35:31
things small small number of input and we are able to clearly see that how the
37:35:36
pattern is going on. So let's take another example.
37:35:43
So these are the values. Let me also denote the index values for these.
37:35:49
Now with every single iteration I'm going to note down the uh in the index
37:35:56
value transition we are making. Okay. So initially we are at this position number five. The maximum jump we can take is a
37:36:02
five step which means that we would end up over here. So initially we would do something like this. So 0 to 5 this is
37:36:09
one one step we take. We are at zero position which means we can't go forward which means we have to backtrack. Which
37:36:16
means that again uh from five we will come back to this zero as index. Now
37:36:22
from five rather than making a jump of five steps we will make jump of four steps and we would end up at this
37:36:28
position four. So from zero we would end up at this position four. Now from this
37:36:34
four the maximum jump we can make is one. So again we will take one step jump and we would end up at this position
37:36:41
five. Again from we are at zero we can't do anything. So we'll have to backtrack. So in order to backtrack we will go to
37:36:48
go back to this position number four. Again we have to backtrack from this position four. We will end up at zero.
37:36:55
Again we will rather than making a jump of four step we'll make a jump of three step and we'll end up over here. So we
37:37:01
end up over here and so on and so forth. So you can see that this uh in this
37:37:06
approach all we are doing is just we are going someplace we are coming back. Again we are going we are going and then
37:37:13
again we are coming back again we are going to some next element we are going to some next element and we are coming
37:37:18
back and suppose this keeps repeating multiple times uh you are essentially
37:37:27
depleting your resources because if you see the time complexity at any single iteration uh or at any single value we
37:37:35
have two possibilities whether we wants to keep this value in our current transition or we do not want to keep our
37:37:41
value keep this value in our current uh path that we are calculating. Which means that the input if we make decision
37:37:49
tree the decision tree would would keep on growing and growing with uh addition of every single value which means that
37:37:57
uh we are basically making lot of decisions and the time complexity in
37:38:03
this scenario would actually be big of 2 to the^ n because at every single position we are making two
37:38:10
possibilities. This is a very bad exponential time complexity which we cannot allow in any scenario.
37:38:18
Okay. So the issue in the brute force approach we had is that we were doing lot of repetitive work because at any
37:38:24
point we found out that we are not able to make any progress from this point. We are still ending up at that point. So
37:38:30
let's see that how can we counter that with a better approach. Suppose we create an additional data structure over
37:38:37
here. So we create a dynamic programmatically additional data structure over here. Uh let's create an
37:38:44
array and in that array we are going to define that at any position can we reach
37:38:50
to this end point and if we identify that yes we can reach to this end point we would basically fill that position as
37:38:57
true and let's see that how it can help us. So if at any point in time we are at
37:39:03
this final position we know that this is the main uh terminating case which means
37:39:09
that we can put true over here. So this final element we can always put true and this would actually become our base
37:39:16
case. Now we have a base case. We are going to start iterating on from right
37:39:22
to left manner and uh we are going to start filling up our DP array to see and
37:39:28
in the DP array the only thing we are mentioning is that at any given location if we are able to reach to this end
37:39:34
point or not if we can we'll just mark it as true otherwise we'll mark it as false. Okay. So now one step over here
37:39:42
this is uh this value has potential to make two jumps uh and it only takes one
37:39:49
jump to get to this last point which means that if we end up at this fourth position we can reach to this fifth
37:39:55
position which is what we want. So over here we can also fill this as true. Now
37:40:01
we are at this zeroth position. From this zeroth position can we reach to this fifth position? No because we
37:40:06
cannot we can basically can't make any jumps. So we'll just fill this as false.
37:40:11
Okay. Now from this one can we end up at this fifth position? So we are going to
37:40:18
now the interesting part comes. Now we are going to check that okay this has possibility of only doing one jump.
37:40:24
Right. So with one jump we can only end up at this third index. Now we only need
37:40:30
to check that in this DP array for this third index if the value is true or false. So in this case this is already
37:40:38
false which means that the maximum we can get to is this third place. From this third place we can't go anywhere.
37:40:44
So we don't even need to check these values. We can only check this the DP table and we can conclude that no we
37:40:51
can't go anywhere forward. So we will put a false over here as well. Now we
37:40:58
are at this third position. Now from this third position we will again do the same check. But thing is this has
37:41:04
potential to do three jumps. Okay. So let's do one jump at a time. So first we
37:41:09
take a jump. If we take a jump of one step, we end up over here. We check over here that this is false. Which means
37:41:15
that this is false. Right? Now we take second jump. With the second jump, we end up at this third position. We check
37:41:22
in this DP array. This is also false, which means that we can't do anything. Now from this third position, we still
37:41:29
have one more possibility that we can take a jump of three uh values. So if we take a jump of three values we end up at
37:41:37
this position value number uh this index number four. So for this index number
37:41:42
four we we see that the value is true. If we find any true which means that we can say that from this second uh this
37:41:51
index uh index number one we can reach to this last end point. And now for this
37:41:56
uh position we need to check that uh it has potential to do two jumps. we will
37:42:02
only check for one jump. So with one jump we will end up at this first uh uh
37:42:08
index that one is true which means that we can fill true over here as well. And in the end we just need to return
37:42:14
whatever of DP of zero we found. So in this case we can determine that this uh
37:42:21
is true which means that we are able to come to final uh end point. So this
37:42:26
solution is very good. It works perfectly fine. Okay. So the time time
37:42:31
and space complexity for this approach would be so the time complexity would be bigo of n² because notice that we need
37:42:40
to do one iteration to go on the to for every single element and sometimes for
37:42:45
any given element we might have to do multiple jumps like we did in this case of three. So in the worst case we might
37:42:51
have to solve this in big of n² time and the space complexity would also be big
37:42:57
of n because we are creating this additional dp array. Now this is still
37:43:03
much better than our brute force approach but our aim is to go into companies like Google, Facebook, Amazon, Apple and whatnot. So those companies
37:43:10
expect the best out of the best solutions. And is this the best out of the best solutions we can do? Actually
37:43:17
no. There is still a better optimal solution. And let me show you how we can get there.
37:43:24
Okay. And this optimal solution is actually based on uh the dynamic programming solution that we just saw.
37:43:31
So in dynamic programming what we are doing is we are creating an additional DP array and we are storing that whether
37:43:38
we can uh reach to this last element or not. The thing is what if rather than
37:43:44
storing this value at any position when we find out that suppose from this
37:43:50
position we find out that yes we are able to reach to this last position. So why do we need to check that whether we
37:43:57
can reach to this last position or not. If at any point amongst these values if
37:44:02
we end up at this position we would still be able to guarantee that we can
37:44:07
reach the last element because we have already checked this this condition. So rather than checking to for this whole
37:44:15
thing if we just check that okay from here if we can reach to this element or not and if this is true we can simply
37:44:22
return true at that moment also and let's see that in action. So let me
37:44:28
clean this up a bit. Let's mark all the index values.
37:44:36
Okay. Initially we create an element called final. And this final element represents the last value in the uh
37:44:45
given input. And initially we set it up to this uh index number five. Right? Now
37:44:51
our aim is that at any point we found out that amongst these values if anyone
37:44:58
can reach this final element then that element by itself becomes this final. So
37:45:04
rather than storing all the values of uh at any given location we are actually
37:45:11
shrinking down our boundary of search. Initially the final is at this fifth
37:45:17
position. Now we are at this second position. So all we need to do is to check that whether our current index I
37:45:25
uh our current index and this current value if sum of these two is actually greater than whatever final we have. So
37:45:31
currently the final we have is this five. So this is the final we have
37:45:37
current sum of these two values becomes 4 + 2 is equal to 6 which is greater than five which means that we can update
37:45:44
the fin value of our final. So now,
37:45:49
so now this becomes our new final and we basically don't care about this
37:45:55
value anymore. Now we are at this third location and we try to see that uh the
37:46:01
index plus its value. So this this becomes 3 + 0. Is it greater than our
37:46:06
final? No, this is not greater than our final because this is three and this is four. Which means that we can't do
37:46:11
anything over here. So we drop this calculation and we check with the next element. So over here we have this two
37:46:18
and we have the value one. So 2 + 1 is this uh greater than four. So greater
37:46:25
than final? No. This is also not true. Which means we can't do anything over here. We again go back. Now this is 1
37:46:31
and this is three. Now 1 + 3. Is this greater than or equal to value four?
37:46:38
Yes, this is greater. This is actually equal to four. Which means that we from this point we can come to this point.
37:46:46
This is what this concludes and which is what we want. Right? So now we know this
37:46:51
information which means that we can update the value of our final again. So now
37:46:57
the value the value of our final would become one. So at this value and now at
37:47:05
this zero position we need to check that whether we can reach to this one or not.
37:47:10
So current so over here the sum of these two value becomes zero plus uh this is
37:47:16
two. So two is definitely greater than the final amount we have is 1 which
37:47:21
means that we can reach over here. So the final element would be shifted to
37:47:27
this point and our at the end of our iteration the final would be zero. So
37:47:33
now the final is zero. After the end of the iteration we only need to check that what is the value of final. If final is
37:47:39
zero, we return true. If final is anything other than zero, we return false. And this is a very good solution.
37:47:47
The whole thing runs in the time complexity of big go of n. And if we see
37:47:53
the space complexity, we are only storing one additional parameter. So we are essentially using constant space and
37:48:00
we are solving this problem. So this is a very efficient solution.
37:48:06
Let's create a variable called final. Oh, I it's Java. I can't use final.
37:48:12
Let's call it final with an extra L. And uh we'll assign it value as uh
37:48:18
nums.length minus one.
37:48:24
And now we will run a for loop and we'll start it from I is equal to uh number of
37:48:30
length nums.length length minus 2 because we already know the result for
37:48:36
uh the array length and we will run it up until we reach to
37:48:42
this zero position we'll do i - and inside the loop we are only going to
37:48:50
check one condition that if uh the current value of i plus nums of i
37:48:58
if they are greater than or equal to whatever the final value we have, we can
37:49:05
uh update the value of this final parameter to whatever the e value we have. And uh yeah, that's that should be
37:49:13
pretty much it. Now we only need to check that if uh the value of this final character is uh zero or not. So if it is
37:49:23
equal to zero, we can return true. Else we can will return false.
37:49:33
Okay, let's try to run the code. Seems like our solution is working. Let's try to submit the code.
37:49:41
Okay, our solution works 100% faster than all the other solutions. This is really good sign and uh this is not
37:49:47
constant time but because we are basically shifting our uh boundary, we
37:49:54
are essentially reducing the number of work we can do we can do. And also if you see the memory usage we are actually
37:49:59
better than uh 86% of all the other solutions. So this was a very small line
37:50:06
of code but this uh small line of code actually requires huge set of
37:50:12
understanding. So see you in the next video. Thank you.
37:50:23
Hello friends. I'm a cloud solutions architect at Microsoft who like making lead code videos. And today we are going to solve an awesome problem called jump
37:50:30
game 2. If you see some of the popular companies who have already asked this question, there are companies like Amazon, Google, Goldman Sachs,
37:50:36
Bloomberg, Door Dash, Uber, Microsoft, Apple, Tesla, Tik Tok, Snapchat and by
37:50:42
dance. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
37:50:49
So this is a lead code medium problem and also very well-liked problem on lead code. Basically in this problem we are
37:50:55
given an array of integer called nums as an input and we are told that we are initially positioned at the first
37:51:01
position inside this given array. Now our aim in this problem is to return the minimum number of jumps required to
37:51:08
reach to the last position. Now you must ask that how are we going to make these jumps? What are the criterias for that?
37:51:14
So the criteria for any jump is that any given value that is presented inside this given array represents the number
37:51:21
of values it can jump. So basically if this one is represented two we can say that it can reach it can either take
37:51:27
like one jump or it can take two jumps and reach to these positions and our aim is to reach this last position. And
37:51:34
basically we need to do this in the minimum number of jumps that is required. Now if you are confused don't
37:51:39
be. I'm actually going to show you a couple of examples uh to understand that how things work. So basically over here
37:51:45
we are given five different values and for these five different values as I mentioned earlier every single value
37:51:51
represents the maximum number of jumps it can take. So this value number two has two possibilities. It can either
37:51:57
take one jump and reach to this position number three or it can take two jumps and reach to this position number one.
37:52:03
Same goes with value number three. It has three options. It can take like one jump, two jump or three jumps and then
37:52:09
uh do that and our aim is to reach the last position from the first position in the minimum number of jumps possible. So
37:52:16
if we see in this example the answer is actually quite evident. We start our position at this value number uh two and
37:52:23
uh if we just take like first jump to reach to this value number three. Okay. So currently the number of jumps we have
37:52:30
taken is one. Now from this value number three if we take another jump of the size three basically we would be able to
37:52:36
reach to the end position and in total we are only taking two jumps to reach to
37:52:41
the end. So basically we need to return two as the answer in this case. If we try to understand the second examples
37:52:47
things are a little bit uh different. So in this case we can only take one jump. So okay so currently the number of jumps
37:52:53
we have taken is one. Now from this one we need to take one more jump to reach to this position. So again the number of
37:52:59
jumps we have taken so far is two. Now from this two we have two options. Either we can take one jump and reach
37:53:05
over here. But that is not the most optimal way. Most optimal way is we take a jump of two steps and reach to
37:53:11
directly to this end point. So basically the answer in this case is going to be three. That we need minimum three jumps
37:53:18
to reach to this last position. And uh in this case we need minimum two jumps to reach to this last position. So this
37:53:25
is what the problem is asking us to find. And uh I know it can look tricky but it's really simple to do it. And uh
37:53:32
let me show you couple of different uh approaches to solve this problem.
37:53:38
Okay. So the first approach that comes to our mind is a brute force approach and in the brute force approach basically we are just going to use the
37:53:45
simple logic. The logic is that at any single position we will try to see that
37:53:50
how many jumps it can take and try to explore all the possibilities and try to find that how many jumps it takes to
37:53:57
reach to the end element and also have like a minimum variable in mind that whenever we find minimum number of jumps
37:54:03
we will keep on adding it over here and eventually when we compute all the calculations we should have a result. So
37:54:08
in this case what we are going to do is that okay this value is two. So first we will consider the possibility of just
37:54:15
taking one jump. So in this case okay if we take one jump we reach over here. Again we have three possibilities over
37:54:21
here but we are only going to take one jump. So again we reach over here. Again this only has one possibility. So we
37:54:26
reach over here and then we reach to the end. So in this case we took in total five jumps to reach to the end. Now
37:54:32
secondly we are going to take like different things. So first we'll take two jumps. Uh so we took two jumps and
37:54:38
now we take one jump every single time and try to see how when we reach to the end and so on and so forth we keep on
37:54:44
repeating the same process with different combinations. Now just by the explanation you can imagine that how
37:54:50
complicated it's going to make things because for every single time you will have to calculate different permutations
37:54:56
and combinations of sums and eventually it's going to lead to very disaster results like if we see time complexity
37:55:03
in this case it's going to be in the order of n factorial because for every single element we will have to compute
37:55:09
the process for all the other elements and that is going to be uh in the order of big of n factorial which is really
37:55:15
really really bad. So we will have to find a better solution and the better solution is actually quite simple. So
37:55:22
let me just directly go to the optimal solution. And now for the optimal solution we are
37:55:28
actually going to use a very interesting concept called greedy concept. And basically we are going to try to make
37:55:34
the biggest jump possible every single time and try to see that where does that leads us. Now being greedy is not good
37:55:41
in real life but in computer science it is like the must thing. So you have to do it. Now for the greedy approach, we
37:55:47
are actually going to keep track of four different variables. So first variable we are going to keep track of is the
37:55:52
index value we are currently at. So let's just name it as index. Uh again we will also have to keep track of the
37:55:58
number of jumps we have made so far. Uh also we will have we will need a variable to keep track of current
37:56:04
maximum variable that we have been able to reach or current maximum value we have been able to reach. And also from
37:56:10
the current index we will have to keep track of that what is the current uh end value we can reach at. So there are four
37:56:17
variables. Let me go over them again. First one is the index value. Second one is the number of jumps we have made so
37:56:23
far. These two are sensible. Third one is to keep track of that what is the current maximum value we have achieved
37:56:29
so far and we will only update it when we find like a better maximum value.
37:56:34
When we go through the example everything will make more sense and the current end defines it is in correlation
37:56:40
with the index value that where does the current end lies and if we are at the
37:56:45
index value then we will have to make some changes. So now let's look at the example and uh currently let's uh
37:56:51
initially assign the values. So initially the number of jumps are zero, current maximum is also zero and current
37:56:57
end is also zero. Uh now we start our journey. So first we come up at this
37:57:02
first index. So whenever we are at the first index, okay, the index value currently is zero. Now the index value
37:57:08
is zero. Now let's just keep on updating these values, right? So currently this has value number one. So if this has
37:57:15
value number one, which means that this zeroth index has the potential to reach
37:57:20
maximum at the first index, which means the current maximum value we can achieve is that okay, this current value is
37:57:27
zero. Now over here it says that it has maximum potential to reach index value number one. So 1 is definitely greater
37:57:33
than zero. So because it is greater than zero we will update the value of current maximum to one that okay this is the
37:57:38
maximum value we have been able to achieve. Now the interesting part comes the current end we were at the current
37:57:45
end was zero because we were at the zero position and also the index value we were at was also zero. So because both
37:57:52
of these values were same which means that in order to get ahead to the next
37:57:58
index which is not the last index again remember I'm repeating in order to get ahead from the current index which is
37:58:05
not the last index we will have to update the current end because currently the current end was also here and the
37:58:11
maximum value was also here but this has the value one. So we have the ability to go to next which means the current end
37:58:17
needs to be updated and whenever both of these are at the same place that means
37:58:22
if we are updating the current end value we will only update the current end value in the condition when we are
37:58:28
making the jump. So again let's just go back to our analysis because the index
37:58:35
value and the current index current end both were same. So because these two
37:58:40
values were same we can define that we need to update their values which means we are taking a jump. So okay so we made
37:58:47
a jump. So we will do jump plus. So currently this value becomes one. But thing is where do we update this current
37:58:55
end to? We will always go this current end to the whatever the maximum value we
37:59:00
have been able to find so far. So current maximum we found is one. So again we are going to include this value
37:59:05
number one over here. Now let me clean this up a bit. So now we are at index
37:59:11
position number one. So we will update the index value. So our current index value is one. Now at this position what
37:59:18
is the maximum it can travel? Maximum it can travel three points. So three is going to be 1 + 3. So that is four. So
37:59:25
now this is the current maximum we can achieve that is four. So we'll compare four with the current maximum we had.
37:59:31
Current maximum is 1. So four is definitely greater than 1 which means it is sensible for us to update the current maximum. So current maximum becomes
37:59:37
four. Now uh we will also have to check that what is the current end. Now current end is still same as the index
37:59:44
value because this was the current end. So which means that anyways we will have to make a jump. So because we are making
37:59:51
a jump we will update the value over here. So currently the number of jumps we have made so far is two and we will
37:59:57
also have to update the value of the current end. So max current end we can reach is position number four because we
38:00:03
already established that that is where the maximum number of jumps we can take. So okay we are good up until this point.
38:00:09
Now again let's make the changes. So now we are at index number two. So let's see
38:00:15
that what story happens at index number two. Now index number two the maximum we
38:00:21
can take jump is one. So if we take one jump we reach at index number three. But the thing is if we check the current max
38:00:28
current max is already four and the maximum we can reach is three. So three is actually less than four. Uh so in
38:00:35
this case we don't need to update the current max. Okay, awesome. We are not updating the current max. And now we
38:00:40
check. Okay, current end is four and the index value is two. So these two are not same because these two are not same. We
38:00:46
don't need to update the current end or the number of jumps that we are taking.
38:00:52
Now okay, now our index value keeps on updating because we are checking this for every single index value. So now we
38:00:59
are at position number three. So now at position number three, we have maximum three possibilities, right? So if we go
38:01:05
to three steps we reach to the index number six. So our current maximum will become six because definitely six is
38:01:12
greater than four. Now we updated our current maximum. Now we also need to check few other things. Okay. So current
38:01:18
end and index value these two are not same. So we are not going to do any changes for now. So now our index value
38:01:25
becomes four. So let's update this. Okay. So this becomes four. Now we are at this fourth position. This only has
38:01:32
possibility of one. So this this will reach to the maximum of five but five is actually less than six. So in this case
38:01:39
we will not update uh the current maximum. Now in this case the index value and current end is both are both
38:01:46
of them are same. So because both of them are same we will have to do the update. So now when we do the update
38:01:52
okay we are going to mark the current end as six because that is what the current maximum we have been able to achieve and also the number of jumps we
38:01:59
are going to take is going to become three. Okay. Now again we keep on repeating the same process. So again our
38:02:05
index value becomes five. Now because with the with the five index value the
38:02:11
maximum we can take is one. So that is going to lead up to six because but we already have a current maximum at six.
38:02:17
So we don't need to do anything. And these two values are not same. So we we are not going to do anything. Now the
38:02:23
index value is at position number six. Now at position number six we are actually able to reach to the end with
38:02:29
just a single jump. So we are going to do that. Okay. Now we reach to the end of the this jump. But the thing is we
38:02:36
are just going to for the sake of simplicity go ahead with this calculation. So the current maximum we
38:02:42
have been able to achieve is going to be seven. That is the end. Now uh current
38:02:47
end and the index value both of these are same. So because both of these are same we will have to update our number
38:02:53
of jumps that we need to take and also we need to update the current end. So current end in this case is going to be
38:02:59
seven. And we are going to check that if the current end reaches to the last position or the size of the array that
38:03:05
means that is the answer and we can break out of the loop and whatever the answer we have been able to find we can
38:03:10
simply return this. So in this case for this example the answer is going to be four that we can return simply and this
38:03:17
is the most beautiful approach of the greedy solution that I have seen so far. Now if we see time and space complexity
38:03:23
in this case the time complexity is so good because we are only going through
38:03:28
every single values and calculating keeping track of four different variables. So time complexity is
38:03:34
actually going to be big of n. So notice that from bigo of n factorial we were
38:03:39
able to bring it down to big of n and all due to the greedy approach that we took. If we see space complexity in this
38:03:46
case the space complexity is actually going to be big of one or constant space. Why? because uh we are not using
38:03:53
anything else apart from like these four values. So that is also a wonderful news.
38:04:01
So let's initialize three variables that we need that is going to be jump current and and current maximum and initially
38:04:07
all the values are going to be zero. Now notice that I'm not using the index value over here and that is because we
38:04:13
can actually use it from our loop directly. Now let's run a for loop to iterate over the given input array. So
38:04:20
now every single time we will check that what is the current maximum we have been able to achieve. So we are basically
38:04:27
going to compare the maximum value amongst the existing current maximum
38:04:32
value or the value of I plus whatever the
38:04:39
value of nums of I for that particular I is and whichever is maximum we are going
38:04:44
to put it in the current maximum. Now we are also going to check one very critical condition that if the given I
38:04:52
is actually equal to the current end we are at. If that is the case which means
38:04:57
we will have to update the value of the jump. So we will do jump++ and we will also have to update the value of the
38:05:02
current end. So current end is in this case going to become the current maximum that we have been able to achieve. And
38:05:09
believe it or not but this concludes the whole solution. After uh we get out of
38:05:15
the loop, we can simply return the jump that we have been able to find. And uh
38:05:20
this should be it. Let's try to run this code. Okay, seems like our solution is
38:05:25
working as expected. Let's submit this code. And if we submit it, this is beating like almost 99.99%
38:05:32
of the solutions in terms of time complexity and in terms of space complexity. This is also very efficient.
38:05:38
So this is a very good solution. And if you see we are just only using a single loop and just like few lines of code to
38:05:45
solve this problem. And uh I will be posting this in the comments so you can check it.
38:06:00
So the lead code problem we are going to solve today is called partition labels. And we can see that this one is a pretty
38:06:05
popular lead code problem. Basically, we are given a string that we want to partition into as many parts as possible
38:06:13
so that every single letter in each of the partition appears at most at one and
38:06:19
not in any other partition. Now note that the partition is done such that after concatenating all the parts in
38:06:26
order, the resulting string would be string s. So we cannot just partition randomly from the middle of the string.
38:06:32
It has to be sequential. Now let's try to understand it with some examples. Let's say that we are given a scenario
38:06:38
like this. Now we want to create maximum partition where every single character only appears in just one partition. So
38:06:44
in this case we can create a partition with this a b a because remember a appears over here and a appears over
38:06:50
here. So they both has to be in the same partition. And then we can create one more partition called d. And notice that
38:06:57
if we combine this ab a d then we would get the resulting string s. Same way for
38:07:02
this one we can create a partition A a because that would fulfill uh that all the characters of A are present. Then we
38:07:09
can create a partition called B C DB because B is present over here and here.
38:07:16
So it has to be part of the same partition. Now for this third one we can create a partition A A. We can also
38:07:21
create a partition C and then we would be creating an individual partition called B and then there would be a
38:07:28
partition called D. And this is what we need to return. So basically in the answer we know don't need to return
38:07:34
something like this the exact partitions but we only need to return the size of
38:07:39
those partitions. So for this example we would return answers such as two and then two and then one and one. So these
38:07:46
are going to be the sizes. Now the brute force solution is actually quite straightforward. We simply take a
38:07:52
character. We iterate over every single remaining values. We see that what is the last point where the character
38:07:58
occurs and then tries to create a partition of that size and we keep on repeating the same process again and
38:08:04
again for every single remaining characters and so on and so forth. Eventually we would get all the
38:08:10
necessary partitions but the thing is this is not the most optimal approach and we can see that this one would run
38:08:15
in big of n square time. So we can do something better and let's try to find
38:08:21
an easy and simplest solution that we can derive from originally uh brainstorming or brute force approach
38:08:27
and that is to use the greedy way to solve this problem. We are going to be very efficient in picking and choosing
38:08:34
how we are going to go forward by selecting the partition. Now the first rule to select any particular partition
38:08:41
is to identify that for any particular character the starting value doesn't
38:08:46
matter but what is going to be the last occurrence for that particular character matters the most because once we
38:08:53
identify that a character is part of any partition then we will have to figure out that what is going to be the last
38:08:59
place this character is going to be placed at that is number one thing. Second thing is apart from being like
38:09:06
finding the last position, we would also have to figure out that this partition makes sense if all the characters
38:09:13
present in this particular partition has the last point either being this value
38:09:20
or before that. I repeat that this only this can only be a partition if every
38:09:27
single unique character that there are present their last point or the last
38:09:32
occurrence would either be less than the index value that we are currently at. So
38:09:38
based on using these two values and some additional variables like the partition end time and the partition starting
38:09:45
variable, we can actually solve this problem very easily and very efficiently. So let's first identify our
38:09:52
first approach that is to find the last occurrence for every single unique character. So let's say that for A the
38:09:58
last occurrence is going to be uh index number two. For B the last occurrence is
38:10:04
going to be index position number one. Okay. So now we have our list of last occurrences for every single character.
38:10:11
After that we can start iterating over any particular given character in this simple fashion on in this given string.
38:10:17
And all we will have to compare is that what is going to be the last occurrence compared to uh its current eth position.
38:10:25
And whichever is going to be the greater value we are going to put it as part of our partition end because that has to be
38:10:31
the partition end. And whenever we find a greater value we would update the partition end that we are currently at.
38:10:37
On top of it if we are at a position where the given E value is equal to the
38:10:42
partition end which means we found out a correct partition. So no other character exist that has a greater last occurrence
38:10:50
compared to our current value and we can mark it as a partition. So we can just add it to our result list. So let's say
38:10:56
that we are also creating a result list to store all the results. Okay. And let's just uh follow our approach. So
38:11:03
first we identified value number A. So for value number A, the last occurrence is located at position number two. So
38:11:09
the partition end has to be at least value two. So we'll mark it over here.
38:11:14
Okay. And then uh the partition start initially is going to be zero. Then we
38:11:19
are going to iterate over value number B. What is the partition end? Partition end is one. One is lesser than value
38:11:25
number two. So which means we can we don't need to update the partition end.
38:11:30
Next current I value we are at is value number A that is located at position number two. So in this case because I is
38:11:38
equal to two and the partition end is also going to be two. We can actually mark these values inside the result. So
38:11:44
currently in the result we are going to have three characters. So that we can determine by finding out position start
38:11:50
minus uh so sorry position end minus position start + one. We'll have to add plus one because we are starting with a
38:11:57
zero index. So in this case first result is going to be value number three. After that we are going to update the position
38:12:03
start value to the partition three uh number three and we are going to reset
38:12:08
the value of partition end. Okay. So currently the partition end would be dep dependent on this particular value C.
38:12:15
Okay. So C for the current C value the last occurrence is six and previous
38:12:21
value was two but six is greater. So we are going to mark six as the current partition end. Now for this D the
38:12:27
partition end is going to be four. So four is lesser than six. So we don't need to do anything over here. Same way
38:12:33
five is lesser than six. So we don't need to do anything over here. Now we are at I is equal to 6 and current
38:12:38
partition end ends at six as well. So in this case once again we are going to do partition end minus partition start plus
38:12:45
one. So we will have four characters in this second partition as well which are these four characters. Now we are at
38:12:52
value uh now the new partition end is going to be value number seven. Okay. So
38:12:57
we mark partition value number seven. And lucky for us, the value we are iterating over for Y is also valued at
38:13:05
value number seven. And by the way, the partition uh start would also be updated to value number seven. So since we found
38:13:13
I is equal to 7 and the partition ending position is also seven. So we can mark
38:13:18
this as a new partition and this is this is only going to contain one element and same way this is also going to contain
38:13:25
one more element and we can mark it as the answer. And this is the whole solution basically. Let's do a quick
38:13:30
recap. First, we created an array that is going to store the last occurrences of every single character. Uh once we
38:13:37
have that, then we can simply go over uh all of these characters one by one. Uh
38:13:43
comparing with the last occurrence, the current position end date and position start value and we can maintain a result
38:13:52
array. And if you see the coding solution, this would become much more sense that how does all of this
38:13:58
operates. Now if we calculate the time and space complexity in this case, the time complexity is going to be big of n
38:14:04
because we will have to iterate over the given input string couple of times. But overall it's just a linear update or the
38:14:10
linear traversal. And the space complexity is also going to be bigo of n or this can be bigo of one depending on
38:14:17
how you perceive it. Because if we are only talking about the lower case English letters then there are only 26
38:14:25
possibilities and we can use a constant amount of space to solve this problem.
38:14:30
So you can debate this with your interviewer that on how they wants to perceive it but both basically both the
38:14:35
approaches would be correct. So the coding solution is going to be quite straightforward. First we are going to check that what is the last occurrence
38:14:42
of every single character. And since there are only 26 characters uh that could be in string s. We can use a
38:14:48
simple array instead of using a hashmap. We can iterate over every single characters and then just mark their uh
38:14:56
position with the appropriate e position and just store it in our array called last occurrence. Step two is to iterate
38:15:03
through the string and determine the partition. For that we will need to have a variable to store the answer and we
38:15:08
are going to initialize our array list called result. We also need couple of variables to keep track of the partition
38:15:14
end and partition start pointers. So uh once we have everything set we say we
38:15:20
are simply going to iterate over the given integer. uh and we are going to mark the current partition end as the
38:15:28
maximum value between the current partition end that we have been able to find and the maximum value of the last
38:15:35
occurrence of the current character we are at. Then if at any given point we
38:15:40
identify that the given I is actually equal to partition end then we can simply find we have simply found a
38:15:47
partition where there does not exist any more characters further than that point.
38:15:53
So we can add that value to the result and then we can start working with our next partition. So we can just update
38:15:59
the value of the partition start and then we can keep on repeating the same process and uh in the end we can simply
38:16:06
result return our result error list. So let's try to run this code.
38:16:14
So the solution is working as expected. Let's submit this code
38:16:22
and our code beats 91% of all the other solutions which is excellent and I will
38:16:27
be posting this in the comments so you can go and check it out from there. Thank you.
38:16:40
The lead code problem we are going to solve now is called merge triplets to form target triplet. Now we can see that
38:16:46
this one is a medium problem and also not very well-like problem but a really important one. Basically a triplet is an
38:16:54
integer array of three integers. Okay, that's fine. And we are given a 2D integer array called triplets with bunch
38:17:01
of different values that contains the pieces of uh triplets which means like values like a, b and c. Okay. Now we are
38:17:09
being told that there is a target triplet x y and zed. Now we need to make
38:17:16
sure that in this given triplets are we able to generate this target uh by doing
38:17:23
the following operation on any number. So basically we can pick any two
38:17:28
triplets from our given triplet array and B if we pick any two triplet
38:17:34
basically we can combine them to create a separate new triplet that is only going to contain three values but that
38:17:40
is going to be the maximum value at each position amongst these two two triplets.
38:17:46
So let me give you an example. Suppose we have a triplet 1 2 and three and we have a triplet let's say four five and
38:17:53
six. So in this case we know that amongst these two the higher value is four then amongst these two the higher
38:18:00
value is five and amongst these two the higher value is six. So if we merge these two triplets basically we can form
38:18:06
an operation like this. So based on this we are being told that we can do as many
38:18:13
number of operations as we need amongst all the triplets that that are given but we are trying to make this target
38:18:19
number. If we can make the target number awesome, we need to return true. If we are not able to make the target number,
38:18:26
then we need to return false. So let's try to see one example and we'll try to
38:18:31
figure out different examples from that. So first one is that let's say that in
38:18:38
any given case we are given these three triplets, right? For these three triplets we need to form a number 2, 7
38:18:45
and five. Now notice that we have the option to do the operation between any two triplets. So let's say that we do
38:18:51
that max operation between these two triplets which means we have value two 5
38:18:57
and 3 at one position and second value is 1 7 and 5. By doing the operation
38:19:04
like the merge operation basically we can pick the maximum amongst the all of these values and we will form a new
38:19:10
triplet that is going to be maximum of these two values. So the value is going to be two. This is going to be maximum.
38:19:16
So value is going to be seven. And this is going to be the maximum. So once again value is going to be five. And notice that this exactly matches the
38:19:23
given input target that we have. So in this case we can return true saying that yes based on the given input we are able
38:19:31
to generate the target value and hence we can make the triplet by merging two
38:19:36
triplets. So let's see that what is going to be the uh brute force approach to solve this problem. Well, it is quite
38:19:42
straightforward that for any given triplets that we currently have, let's say that we are given in total five
38:19:49
triplets and I'm just marking them as A, B, C, D and E. And for each of these
38:19:54
five triplets, we have the option to do the merge operation. So if the brute
38:20:00
force ways that we do merge operation amongst these two triplets, we do merge operation amongst uh these two triplets
38:20:07
and so on and so forth. We keep on repeating and every single time we compare it with the target value to see
38:20:13
if we are able to generate the target value or not and eventually if we can we would find the correct answer but this
38:20:19
would yield in big of n² time where n is the number of triplets that we currently
38:20:25
have which is an inefficient approach. we'll need to find a better approach and the optimal solution in this case comes
38:20:32
from doing things in the most simplest manner optimally and that is to use a
38:20:38
greedy approach. So let's say that this is the example that we are currently given. Now notice that whenever we are
38:20:46
iterating over any particular um triplet we should always compare it with the
38:20:52
target to determine that is this a triplet of interest or not. And the
38:20:57
comparison should only contain two items. First thing is that whether if
38:21:03
each of these three values if all of these are lesser than the target value then and then only it is a triplet of
38:21:11
interest for us. Uh otherwise we need to move on to the next triplet. And why?
38:21:16
Let's try to understand. Let's say that currently we are given a triplet 2 six and five. And we are given the target to
38:21:22
be 4 66. Okay. So in this case we can notice that every single value so 2 6
38:21:29
and 5 comparing with 4 6 and 6 notice that every single value inside this
38:21:35
triplet is actually less than or equal to the target triplet that we have which
38:21:40
means this can be a potential uh candidate that we can use in future for
38:21:46
the merge operation. Now the thing is if we are going to use this for the merge operation then we should just put this
38:21:53
put this on a side uh noting that we found a triplet which can be of potential use to us. Uh at the same time
38:22:01
we should also have to keep track of a variable that what if we already found a
38:22:06
triplet that we are all anyways going to find the optimal solution with. And in
38:22:12
order to do do that we will have to basically compare the given triplet with
38:22:17
the target triplet and keep track of the maximum value that we are able to generate from both of these triplets and
38:22:24
just store that information. So let's say in this case we can notice that the because this is a triplet of interest
38:22:32
then we are going to store the maximum value amongst these two these two and these two and notice we are having a
38:22:38
condition that this has to be smaller or equal to the target which means either
38:22:44
we can have all the values that are going to be smaller than target or it is equal to target which means we would
38:22:50
never exceed target in this approach. So in the maximum variable we are going to compare the max values. So we are going
38:22:56
to this is going to be four. This is going to be six. And once again this is going to be six. Okay. So we took care
38:23:03
of this triplet. Now let's move on to the next triplet. Once again in the next triplet we have a value called 7 4 and
38:23:10
6. Now notice that for this one for 7 4 and 6 we did find a triplet that we
38:23:17
currently have over here that is of potential interest uh could to target or
38:23:23
not. So notice that the very first value seven and four. So 7 is greater than
38:23:28
four. Which means if we do merge operation with this triplet then all we are always going to have first value
38:23:35
that is going to be greater than the target value which means this would not be a use for us. So we should just
38:23:40
simply skip over this triplet because we should not use this triplet to merge with anyone else. Okay. Next we have
38:23:47
this value 4 and six. So let's try to see that if we use this value what is
38:23:52
going to be the um expected range or expected triplets we are going to be fine. So in this case basically once
38:24:00
again we compare four with four so this is equal four with six so this is lesser and six with six so this is equal. So
38:24:07
once again this can be a potential uh triplet that we can use. So now let's
38:24:12
try to do the max operation in this case. So the current values are 4 4 and six. So we are doing four, four and six
38:24:19
and we are comparing it with the target which is four, six and four. So now notice that maximum amongst these two is
38:24:25
going to be four. So we add four over here. Maximum amongst these two once again is going to be six and maximum
38:24:31
amongst these two is going to be six. And now in the end we are going to have
38:24:36
maximum variable that is going to contain values 4, 6 and six over here. And meanwhile we are going to have
38:24:42
another uh target value that we were trying to achieve and that was also 4 6
38:24:47
and six. So notice that because both of these values match we can simply say that yes there exist a triplet that we
38:24:54
can generate by merging other triplets. And if we cannot find this maximum value
38:25:00
which means there does not exist a a triplet that is of a good use to us. So in that case we would have returned
38:25:06
false. So if we if you see approach for this solution then we can simply run it in big of n where n defines the number
38:25:13
of triplets and in terms of space complexity we are not adding any additional space. So this is going to be
38:25:19
big of one as well. So I hope this solution makes sense. Now let's quickly see the coding approach. The coding
38:25:25
solution is quite straightforward. First we are going to initialize an array with size three uh naming it as max values.
38:25:31
Then we are going to iterate over every single triplet that we are given inside our triplets 2D array. And for each of
38:25:39
the pair we are going to check that if the current triplet that we have will it
38:25:44
be contributing towards making the target or not. So we are checking that if the given triplet uh position the
38:25:50
value the first value is less than the target less than or equal to target second value is less than or equal to
38:25:56
target and third value is less than or equal to target. If that is the case then we are going to simply update the
38:26:02
maximum values we have been able to achieve based on the given current triplet and the target values. Now
38:26:08
remember because we are considering triplet values to be less than or equal
38:26:15
which means if uh the only case where we have the target value uh set as it is is
38:26:23
if the given triplet value is also same as target value that subsequent value. So we are going to store the values for
38:26:30
all three parameters and keep on repeating the same process for every single given triplets in a greedy
38:26:36
fashion. In the end we simply have to check that whether the three values present inside our array match the
38:26:42
target values uh that are present. If that is the case we can return true otherwise we can return false. So let's
38:26:47
try to run this code. Okay seems like our solution is working
38:26:54
as expected. Let's submit this code.
38:26:59
And our code runs beautifully and uh it is pretty fast. So I will be posting the solution in the comments so you can
38:27:05
check it out from there. Thank you.
38:27:17
The lead code problem we are going to solve now is called gas station. And we can see that this one is a lead code medium problem and also a very very very
38:27:24
well-like problem. Uh the statement is quite straightforward that there are n gas stations along a circular route
38:27:31
where the amount of gas at any particular station is defined in the
38:27:37
array gas fi and then uh we are told that we have a car with unlimited gas
38:27:42
tank that cost cost of i gas to travel from i station to the next i +1 station.
38:27:50
Let's re do a quick recap. Basically we have we are given two arrays. First array is called gas and second array is
38:27:56
called cost. Basically gas any particular value inside the gas array defines how much oil or how much gas we
38:28:03
can fill in the tank at that particular location. Cost at that station defines that if we have to move to the next stop
38:28:11
uh what is going to be the cost in terms of gas amount. So based on distance you can understand it that way. Now we begin
38:28:18
our journey with an empty tank at one of the gas stations. Okay. Now we have uh
38:28:24
basically need to make sure that given these two arrays uh we can start from
38:28:31
any particular gas station's index and we need to check that if from that gas
38:28:36
station's index are we able to travel around the entire circuit once in a clockw clockwise direction. If that is
38:28:44
the case then we need to return the location of that index. If that is not the case, we need to return minus one.
38:28:50
And we are guaranteed that we would be able to find a solution. So if there exist a station, there has to be only
38:28:56
one station that can fulfill that property. Otherwise, it would be minus one. There would not be any duplicated
38:29:02
answers. So let's try to understand this with an example. Uh currently we are given a variable called gas and we are
38:29:09
also given variable called cost. Uh at any particular uh index position, this is the amount of gas we can fill in the
38:29:16
tank. But if we need to go to the next stop then this is going to be the cost
38:29:21
associated with that and so on and so forth. So let's try to see that what would be the answer in this case. Let's
38:29:27
say that suppose we start our journey from index position zero which means currently our car has u so let's just
38:29:34
mention that what is going to be the uh tank uh amount of gas in the tank. Okay.
38:29:39
So currently tank has empty so no gas at all at position number one we would be
38:29:45
able to fill in one amount of gas. So currently tank has only one amount of gas. Now let's say that if we need to
38:29:52
reach to next position uh index position number one then we will have to pay this cost. If we were to pay this cost it
38:30:00
would be 1 minus 3. So basically we our tank would go in negative. So we would not be able to reach to this position
38:30:06
number two from tank number one. So we can clearly say that option zero it does
38:30:11
not work. Same way we can also check that from option number one currently
38:30:17
our tank would be initially zero. Okay let's just repeat the calculation. So this is going to be zero but now we can
38:30:23
fill in 10 + 2. So now the gas would be two. But if we have to get to option
38:30:28
number three then we would have to spend four units or 4 L of gas. Which means 2
38:30:34
- 4 would become minus2. Once again we would not be able to reach to uh item number four. So that would also not
38:30:41
work. So let's just start our iteration from this third index position. Once
38:30:46
again repeating the same logic. Currently tank is going to be zero but we can add tank as three. So three and
38:30:54
uh but if we have to reach to next station we the cost is five. So 3 - 5 once again this would also not work. So
38:31:01
now we are at this uh index position number three. So currently our tank is
38:31:06
going to be zero. So we can add value number four. So now tank has 4 L of gas.
38:31:12
If we have to reach to value number five then we need to spend one liter of gas. So once again this is also going to be 4
38:31:19
minus one. So basically when we reach to this index position number five our tank
38:31:24
would have three units of gas. Once again at this position we would fill in five units of gas. So this is going to
38:31:30
be 3 + 5. But now from this in the clockwide clockwise direction basically we'll need to reach to station number
38:31:36
one but we will have to pay cost of two. So 3 + 5 - 2. So overall this is going to become uh once again six. So we are
38:31:46
going to have six units of gas when we reach to this position number one. Once
38:31:51
again over here we will add one unit of gas. But in order to reach to next
38:31:56
element we will have to spend three units of gas. So now when we reach to this index position number two, our gas
38:32:02
is going to be uh 6 + 1 - 3. So 7 - 3. So basically this is going to be four.
38:32:09
Once again from this position number two uh we need to reach to position number three. So 4 + 2 minus we will have to
38:32:16
spend the four units of gas. So basically this is going to become two. And at this position once again we will
38:32:23
uh we will we get three units of gas. So 2 + 3 minus if we have to reach to next
38:32:29
which is from where we started then basically it's going to be five. So 2 +
38:32:34
3 - 5 is going to become uh zero. So basically we would be able to reach to
38:32:39
uh unit number four and this is going to be the starting point if we were to complete the whole circuit. So we'll
38:32:46
need to return the index position. So we can return three as the answer over here. And I know the explanation took a
38:32:52
lot of time to understand what this problem statement is. But basically this is actually the whole solution as well
38:32:59
because in order to solve this problem we don't need to use any special data structure or any special architecture.
38:33:05
Basically, if we just follow the most simple basic rule that we are going to
38:33:10
start our iteration from the very first index and from this very first index position, we are going to check that are
38:33:17
we going in a scenario where our current tank goes negative. If the current tank
38:33:22
goes negative, we can simply choose the starting point as the next element. And
38:33:28
once again, if it goes negative, we can choose the starting point as next element. And we will keep on repeating
38:33:33
the same process. The moment the tank goes into negative, we will just update the tank value to become zero. And that
38:33:39
is the whole logic of this problem to solve this problem. Now let's talk about some of the critical possibilities.
38:33:45
Number one scenario is the only way we are not able to complete the whole circuit is a very simple logic that is
38:33:52
that if the given gas is going to be less than the total number of cost. If
38:33:57
that is the case, cost is higher. So we would not be able to complete the full circuit circ circuit. And we can
38:34:03
calculate this immediately basically by summing up all the values that are currently present in both gas and cost
38:34:09
arrays. And we can just compare those values. So if that is the case, we can simply return minus one immediately
38:34:14
saying that this problem cannot be solved. If that is not the case, then we will simply follow the most common most
38:34:21
logical thing that humans are really good at and that is called greedy approach. that we are simply going to
38:34:27
take the first value try the solution. If solution works great if we at any
38:34:32
given moment find the tank goes into negative then we will just pick the next value. So over here for the same problem
38:34:38
I have just presented it in a different manner. Currently we have our index position stored inside. So 0 1 2 3 and
38:34:47
four. Now this second circle defines that how how much amount of gas can we get at any particular location and the
38:34:54
values located at these gates define that if we have to jump from gate number one to gate number two then we will have
38:35:01
to spend three units of gas and which we can sub subtract. So basically the solution is that we will start uh our
38:35:09
greedy approach by iterating at value number one with initially the tank is going to be zero and then we will just
38:35:16
repeat the same exercise we did. So we will check okay over here we can add one unit of tank but this is going to be
38:35:22
three units of tank to reach to value number two. So tank would go into negative. So basically we would choose
38:35:27
our starting point over here uh by resetting the tank to be zero. Once again two and this is four. So tank goes
38:35:34
into negative. So once again we would choose our starting value to be index position number two. Once again tank
38:35:40
goes into negative. So once again we would choose our starting index to be this. The moment we find a starting index that where the tank does not go
38:35:46
negative, we would try to iterate over and see if we are able to complete the whole journey or whole transaction. And
38:35:52
basically we should be able to do it in this case because we know that we have a starting point where the tank does not
38:35:59
go negative from to when we started trading. And secondly uh the total cost
38:36:06
of basically um total cost is basically uh not less not greater than uh the
38:36:14
total number of guests. So that's why we know that the answer should not be minus one and uh just that's it. So in this
38:36:21
case we would return three as the answer. If we have to calculate time and space complexity it is quite straightforward. for time complexity.
38:36:28
Basically, this can be done because of end time if we apply the greedy approach and we do some slight tweaks with the
38:36:34
code. So the tweaks with the code I'm going to explain you when we get when we actually get to the coding portion and
38:36:40
for the space complexity well we are not using any additional space to solve this problem. So basically this is going to
38:36:46
be big of one. So which is quite beautiful. Now let's just quickly see the coding solution.
38:36:52
So the solution is quite straightforward. First we are going to have few variables. Uh they are going to
38:36:57
be initialized at zero. First one is total gas and total cost both are initialized at zero. Then we have tank
38:37:03
and then we have starting index. Then we are going to a simple for loop that is it going to iterate over every single
38:37:09
starting point in the given input. We are going to have two variables total gas and total cost that is going to be
38:37:15
continuously adding the total amount of gas and total amount of cost. We have for the current proportion of gas that
38:37:23
can live inside the tank is going to be calculated by adding the current gas
38:37:29
with the current tank value and reducing or removing the cost of the current E
38:37:34
position. Then we are checking for a simple condition that if the tank goes into negative then the starting index
38:37:41
that was originally at zero now needs to be at i + 1 position because we identify
38:37:47
that the current i position does not work and then the current value of the total amount of gas inside the tank is
38:37:53
also going to be zero. Then we are going to check at if at any given moment the
38:37:59
total amount of gas becomes less than the total amount of uh cost after the
38:38:06
running of whole for loop. Then if that is the case, we can simply return minus one. And if that is not the case, we
38:38:13
simply return the starting index. And this is the whole solution. Let's try to run the code.
38:38:22
Okay, seems like our solution is working beautifully. Let's submit this code
38:38:28
and our code beats 99.29% of all the other solutions which is exceptionally fast. So pretty good. And
38:38:36
once again I will be posting this solution in our GitHub repository. So feel free to go ahead and check it out from there. Thank you.
38:38:51
Hello friends. Hope you are having a fantastic day today. So now we are going to solve an awesome lead code problem called hand of straits. Now we can see
38:38:58
that this one is a medium problem and also a very well-like problem on lead code. Let's understand the problem
38:39:04
statement. We have a girl named Alice who has some number of cards and she wants to rearrange these cards into a
38:39:11
groups such that each group of the size group size consists of group size
38:39:18
consecutive cards. So let's try to understand what this means. Basically we are given an integer array called hand
38:39:24
that defines bunch of different values inside a deck of cards and at any given
38:39:30
integer I is the value return for that particular hand. Now we are also given
38:39:35
another variable called group size. Now we need to check that whether we can
38:39:40
divide all of these hands in a group in group sizes like groups of the these
38:39:46
group sizes such that that all of the rearrange groups contains consecutive
38:39:52
cards and we can rearrange all the groups. So let's try to understand this with an example and then it would make much more sense. Let's say that we are
38:39:59
currently given the hand or deck of hands like this and we are given the group size to be three. So let's see
38:40:04
that can we create the different uh three size groups. So first group we can
38:40:10
create is going to be cards 1 to three. Now notice that there is a condition when we when we are trying to create the
38:40:15
groups that every single card inside the group has to be consecutive. So we can
38:40:20
create this one group. Second group we can create is using these three characters and that is 2 3 and four. And
38:40:26
third group we can create is using 6 7 and 8. So now notice that in this case
38:40:32
we used all of the cards that were currently given to us and we divided them into the size of three and each
38:40:39
group contains the cards that were coming in consecutively. So in this case
38:40:44
we can say that we can create the hand of straits using this. So we will return true in this case. Let's take one more
38:40:51
example. Suppose the given hand is values 1 2 3 4 and five. And in this
38:40:57
case we are given the group size to be four. So in this case we can create a group of size four with these four
38:41:05
characters or with these four characters both of which are going to have consecutive values. So values would be 1
38:41:11
2 3 and four. The thing is we would still have one value one more value left that is going to be left out that we
38:41:17
cannot use. So in this case we can return false because we are not able to create or use every single card inside
38:41:24
our hands array. Let's take just one more example. Let's say that currently the values given are 1 2 3 and 5 6 and
38:41:34
8. And in this case the group where that we are trying to create is of size three. So we can see that we can create
38:41:40
a group 1 2 3 like this. No issues with this. We can also create a group of three cards using five 6 and 8. But
38:41:46
thing is this is not going to be a correct group because we need to create a group that only contains consecutive
38:41:52
elements and five six and eights are not consecutive cards. If this were to be five, six and seven then it would have
38:41:58
worked. So because of that for this particular example we will have to return false. So that's it. This
38:42:05
completes my explanation on what the problem statement is actually asking us to solve. Let's see that what is going
38:42:11
to be the optimal approach to solve this problem. Well, the idea is quite straightforward. What I'm suggesting is
38:42:18
that we are given currently the hands and we are also given uh group sizes.
38:42:24
Now we know that for this particular given group sizes we will have to create groups. The values inside the group has
38:42:31
to be consecutive. So first thing that comes to our mind is that if we are doing deal dealing with consecutive or
38:42:37
subsequent values why don't we just simply sort the given input of hands and then try to start creating groups
38:42:44
according to that. Do you think that approach would work? Let's try to see that approach in exam action. Let's say
38:42:50
that this is the current hand that we are given. Now we are trying to use our first approach where we are going to
38:42:56
sort every single value inside our hand array and try to create groups of size three. So the sorted hand is going to
38:43:03
look something like this. Now notice in this problem if we try to create groups
38:43:08
of three we would not be able to make consecutive groups. We would run into this issue. If we create a group of
38:43:13
three we would have a group that looks like 1 2 and two. And based on this we can just say that this is a false group
38:43:20
and we cannot make sense of it. uh but this would not be the correct correct assumption. Correct assumption would be
38:43:25
that if we identify two values that are same in frequency then we only need to
38:43:31
consider the first value for the partition of first group. So the idea in this case would be that we would create
38:43:36
a group that is going to be 1 2 then we found a repeated character. So we would ignore this one and add value number
38:43:43
three into a group. After creating this group we will check that whether there has been any values that are currently
38:43:49
left. So yes, this two has been left. So let's use the same operation. So now we are going to create one more group using
38:43:55
this two. Now notice that we have already used this three in the first group. So we are going to be eliminating
38:44:00
that and then we can have we will have values three and four in this case. So we can also repeat the same operation
38:44:07
and then uh after all the values that we have currently used, we will keep on trying to make partition and trying to
38:44:13
check that whether they follow the property of them being consecutive or not. So in this case based on this
38:44:19
approach we can actually find the solution which means number one there are few assumptions we can make based on
38:44:25
this. Number one sorting is going to be greatly helpful. Second thing is we come
38:44:30
into the issue of duplicated numbers. So we will need to know that what is the
38:44:35
frequency of every single character and if we can combine these two values store
38:44:41
that information that have the sorted values of all the unique values that are
38:44:46
present and have the frequency that that how many times they are currently present. It would be easy for us to make
38:44:52
these groups and if we are able to make subsequent groups that follow the all the property and we are able to use
38:44:59
every single value inside the hand we can return true or we can return false. So using this what I'm suggesting is
38:45:06
that we actually use something smartly. We use a a hashmap and we use a sorting
38:45:14
approach. Now the thing is why are we why am I suggesting to use the hashmap? because we are dealing with uh unique
38:45:21
entries and for each of the unique entry we have different frequency and this is
38:45:27
what I'm suggesting that we store as part of the hashmap where as a key we are going to store that what is the
38:45:33
current value of the hand and as it subsequent value we are going to store that how many times that hand has been
38:45:39
repeated in any particular iteration. Next after sorting this information we
38:45:44
will have to sort all of these given keys because we are trying to generate consecutive values one by one. So
38:45:52
logically why don't we just combine hashmap and sorting at the same time where we can simply use a tree map that
38:46:00
is going to have best of both worlds that that can access and fetch all the elements in big of one time and it can
38:46:07
insert all the elements in big of login time for the frequency and stuff like that because based on the key value so
38:46:13
this is going to be an efficient approach. So now what I'm suggesting is that we are currently given our hand
38:46:19
that we are we are going to be dealing with for this particular hand. What we are going to do is we are going to
38:46:25
create a tree map. This tree map is going to contain the unique value plus
38:46:31
their frequencies and for these two using these two values we will start creating groups of bunch of different
38:46:38
numbers. And we will need to make sure that the starting if the starting value of group is let's say five and the group
38:46:45
has to be of size three then next value has to be six and next value has to be seven. If we can find six over here
38:46:51
that's great. If we cannot find six at any given moment we can directly return false saying that this group is not
38:46:56
being able to make. So let's try to see my solution in action. So now based on
38:47:02
the hand we have our tree map ready. Notice in the tree map we have every single key or the hand value is
38:47:09
currently sorted and we also have the frequency that how many times this is present. Now we need to create the group
38:47:16
size three for every single value. Uh so the idea would be that for very first
38:47:21
group we are going to take the smallest value out and we are going to reduce its frequ frequency and this is going to
38:47:27
give us the starting point for that particular group. So starting point is going to be one which means this has to
38:47:33
be a group of size three. So next subsequent element that should be in the group has to be value number two. But
38:47:40
thing is we are not sure if two is present or not. And lucky for us we can check that immediately that whether two
38:47:46
is present or not. By the way when we took this one out we would have reduced it frequency. So we can reduce the
38:47:52
frequency to zero. The moment frequency becomes zero it would make sense to el completely eliminate that element rather
38:47:58
than just storing it. So we can eliminate three. Now we are looking for two. We found two and which means we can
38:48:04
also reduce the frequency of two. So now the frequency is going to be one. Next thing should be three. So we are trying
38:48:10
to find a three. And we also found a three. Over here we are also going to reduce its frequency from one uh 2 to
38:48:16
one. So now this is also going to be one. And we created our first group. Now for the second group once again we will
38:48:23
check inside our hashmap or tree map that what is the smallest element. And this is going to be the very first value
38:48:28
inside our tree that is starting point is value number two. So now we are going to use value number two over here which
38:48:35
means its frequency is going to become zero. If the frequency becomes zero we can mark it as zero. And then uh next
38:48:41
element should be three. So we will check that whether three is present. Yes, three is present. So we are also
38:48:46
going to mark its frequency to zero. Once this becomes zero, we can also eliminate this value. And we can also uh
38:48:53
now we are looking for next element to be four. Four is also present and we can mark four as counted. So we can remove
38:48:59
that element and close this group. Now after closing this group we have basically deleted all the elements
38:49:05
before that. Now once again we will have to create a new group. Then that group starting point has to be six. So we'll
38:49:11
going to mark six over here and then which means now we are looking for seven and eight. And lucky for us seven and
38:49:17
eight are also present. So we can just mark these as visited. And then in the end notice that now we currently don't
38:49:24
have any value inside our tree map and because we did not find any at any place
38:49:30
uh where we could not find an element. So in this case we can return true. Now
38:49:36
let's say that in the same example instead of this being seven let's say that this value would have been nine. So
38:49:42
in this case what would have happened that we would have values such as six
38:49:47
and the frequency of the value is going to be that six is present one time. Uh 8
38:49:52
is present one time and 9 is going to be present one time. Over here we find that the starting point has to be six. Now
38:49:59
for this sub this group to exist we will have to find value number seven. But seven would not have been present over
38:50:05
here. The moment we identify such thing like this we could have written false immediately. So this is just for you to
38:50:12
understand that under which scenario we would return false. And basically this is the whole solution. Now you can see
38:50:18
how beautiful we are doing things. Uh if we calculate time and space complexity in this case the time complexity is
38:50:23
going to be big of n log n. Why n login? Because it takes us login time to add all the entries inside our uh tree map.
38:50:31
In terms of space complexity because we are using an additional tree map. It is going to be big of n. But we can manage
38:50:36
that. Now on top of it we can also do one more optimization that if let's say
38:50:42
the given number of hands is currently 10 and if the given group is equal to three. So if the total cards are 10 do
38:50:49
we even need to check that can we make all the groups of size three? No. Why? Because three we can only create like
38:50:55
the group for nine cards and there is still going to be one more left out card. So initially we can always check
38:51:02
that whatever the size of the given currently h is if that is going to be
38:51:07
divisible by uh the given group size or not and this value has the remainder has to be zero. If that is the case then
38:51:13
only we will move forward. So this would be a way for us to eliminate few like bad and edge cases. Uh and now let's see
38:51:20
the coding approach. Now for the coding solution, first thing we are going to check is to see that
38:51:26
whether the given length of all the hands, so all the cards that we currently have, if that is divisible by
38:51:33
group of zero. If that is not the case, then we can directly return false because for sure we would not be able to
38:51:39
make the group of that particular group sizes if this is not divisible by zero. If that is not the case, we are going to
38:51:45
initialize a tree map uh where we are using hashmap in combination with tree map because we want to access the keys
38:51:53
in a particular order. And now we are going to be counting every single card. So we are going to iterate over each of
38:52:00
the card that is currently present inside our hand array and we are going to be adding that to our tree map where
38:52:06
we are going to define that if that card is present as the key then we simply update its frequency. If that is not the
38:52:12
case, we create a new entry. Then we attempt to form groups where we are
38:52:17
first of all in the outer loop checking that while the we still have present
38:52:22
cards inside our key tree map, we are going to do the following where first we
38:52:27
are going to initialize the first key or the first starting point of the first
38:52:32
group with the smallest key. And notice that because we are using tree map we
38:52:37
can actually just keep on accessing the keys directly because they would be stored in a sorted manner. Then we are
38:52:44
going to iterate over uh the for loop focusing on each particular group sizes
38:52:51
where we are checking that what is the current card that is going to be first plus i. Then we are going to check if
38:52:57
that if the we have that current card inside our tree map or not. If we do not
38:53:03
have that value inside the tree map, we can simply return false immediately because we cannot make consecutive
38:53:09
groups. If that is not the case, we are simply going to add that value. Then we are going to reduce the value or the
38:53:16
decrease um decrease the count because we are removing the card and then we are checking that if the given count is
38:53:22
equal to one then we can simply remove that card completely from our tree map. If that is not the case, we simply
38:53:28
reduce its frequency and repeat the same operation. If we do get out of this loop which means we are able to get out of
38:53:35
every single uh card and use every single card to create the appropriate group sizes and which means we need to
38:53:42
return true in the end. So this is the whole solution. Let's try to run our approach.
38:53:49
Seems like our solution works beautifully. Let's submit this code
38:53:57
and our code beats good chunk of uh solutions. It is not the best and there are still improvements can make can be
38:54:03
made but given the time frame this is a good approach and uh the solution is
38:54:08
present inside our GitHub repository. So feel free to go ahead and check it out from there. Thank you.
38:54:22
So the lead code problem we are going to solve now is called valid parenthesis string. We can see that this one is a lead code medium problem and also a very
38:54:28
well-like problem. Basically we are given a string s that contains only three types of characters uh open
38:54:34
parenthesis, closed parenthesis and a star. Now we need to return true if the given string is valid and there are some
38:54:41
definitions given on what is valid. Basically any left parenthesis must have a corresponding right parenthesis.
38:54:47
That's fair. Same way any right parenthesis must have a corresponding left parenthesis. Uh next point is that
38:54:53
left parenthesis means opening parenthesis must go before the corresponding closing parenthesis. So
38:54:58
this is valid. But if we have like this then this is not valid. Okay. And last one is that if we are given star at any
38:55:05
moment then we can consider star to be whatever we want. So we can treat it as a right parenthesis or a closing
38:55:12
parenthesis or an open parenthesis or we can also consider it as an empty string. So that makes no difference. So let's
38:55:18
try to see some examples. Suppose we are given a a parenthesis like this. This one is a valid. If we are given a
38:55:24
parenthesis like this once again this is a valid. If we are given a parenthesis that contains star once again this is a
38:55:31
valid in this case we are treating the star to be an empty string which means we are basically left with this. Uh we
38:55:36
can also say that this is also a valid uh string and so on and so forth. So the
38:55:42
only scenarios where it is not valid is if we are dealing with number of uh like out of order parenthesis or we are
38:55:49
dealing with multiple parentheses of being like this and only one parenthesis like this. So this is also not valid. So
38:55:56
let's try to understand the most common logic on how we can pursue solving this problem. Now we know that if we are only
38:56:03
dealing with working with problems that only contains parenthesis, we can simply use a stack and solve this problem very
38:56:11
easily, very efficiently. There are like lot of different examples of that. I would no go not go in depth in this case
38:56:17
because the important thing for this problem is this asterisk. So whenever we are dealing with an asterisk, we have
38:56:24
three possibilities. We can either consider it to be an open parenthesis. We can consider it to be an empty string
38:56:29
or we can consider it to be a closed parenthesis. So in each of the cases, let's say that if we are dealing with
38:56:35
multiple stars, there can be many possible combinations and permutations that we should be able to make. But that
38:56:42
adds more and more complexity to our problem because let's say that we are given a string like this. Now in this
38:56:48
case uh we need to basically have option over here to choose three different
38:56:53
entries for and for each three different options we have another way to choose three more different options and so on
38:57:00
and so forth. So we can make many many different possible combinations. So we'll have to do things smartly. So one
38:57:06
s sol solution I'm suggesting in this case is that we use greedy approach and basically we iterate over the given
38:57:12
input in just a single fashion and we keep track of the number of open
38:57:18
parenthesis and we also decide that what is the maximum number of open parentheses that we currently can have
38:57:26
depending on the star value and what is going to be the minimum number of open parentheses we can have depending on the
38:57:33
given star value. Now there are two possibilities. One possibility is that for any particular star if we treat it
38:57:40
as an open parenthesis which means there is one more open parenthesis left for us
38:57:45
to deal with. So in that case we can add basically that value to the max
38:57:50
character or we can treat the star as an empty string or a closed parenthesis. In
38:57:56
this case we have one less open parenthesis that we need to deal with. So in this case we would update the
38:58:02
value for the minimum character. So let me just walk you through the solution I'm suggesting. Let's say that we are
38:58:07
currently given an input like this. So in this case we are going to simply have
38:58:13
a few rules for two variables that I'm suggesting. First variable the variable's name is maximum open. Okay.
38:58:21
And second one is minimum open. Now for each of this we are keeping track that
38:58:27
what are the maximum number of untouched open parentheses we have and what is the
38:58:33
minimum number of untouched open parentheses we have. The logic is quite straightforward. We are simply going to
38:58:39
follow few rules. If the given input character is an open parenthesis then we
38:58:44
will have to increment at both the places. So we are going to increment at max and min. If it is a closed
38:58:49
parenthesis which means there is one less open parenthesis for us to deal with. So in this case we would decrement
38:58:56
at both minimum open and maximum open variables and we are going to initialize these with value zero. And if the given
38:59:04
value is star in this case we have two possibilities. So there is one possibility we treat this as an open
38:59:10
parenthesis or we treat this as an closed parenthesis or an empty string. So if we are treating it as an open
38:59:17
parenthesis which means there is one more open parenthesis left for us to
38:59:23
check. So we are going to increment at our max open. So for max open we are
38:59:29
going to update the value whenever we encounter a star. And whenever we encounter star we can also treat it as a
38:59:34
closing bracket. So we will decrement the value at the minimum variable that
38:59:40
we have stored. And this are the rules that we are going to follow. Now uh there are a couple of conditions that
38:59:45
would allow us to solve this problem. Basically find the uh lose cases. So
38:59:52
first case is that if at any given mo point we identify that given number of
38:59:57
maximum open parentheses go into negative which means that there are too many uh too few open parenthesis and too
39:00:06
many unopened parenthesis because remember when this can go into negative whenever we have a closed parenthesis
39:00:13
then we decrement the value. So let's say that if for the given example if the first character in itself is a closed
39:00:19
parenthesis then we would have decremented the value for maximum open and minimum open. So in this case the
39:00:25
maximum open would have become negative. So we can say that now even if this is like the most valid string this is also
39:00:31
this is always going to be not valid because it has an open parenthesis where we don't have a corresponding closed
39:00:37
parenthesis. So this is one scenario that we can keep track of. Second scenario is that at the end our goal is
39:00:45
to ensure that there are no untouched or there are no left open parenthesis. So
39:00:52
let's say that we iterate over the entire given input using these three rules and we find that there are no open
39:00:59
parenthesis which means the min open is zero then we can simply return zero as the answer. Now next thing is uh we have
39:01:06
a possibility where if we are encountering a star we are we are basically reducing the value of the min
39:01:14
parameter. So min parameter can still go into negative but the thing is this would not directly say that we are
39:01:21
dealing with an invalid string. So in this case if for some reason the minimum variable goes negative then we are
39:01:29
simply going to just start it back to zero uh treating that there are no no
39:01:34
open parenthesis left for us to check and I know that uh there are a lot of
39:01:40
rules that I just talked about but the thing is if you just understood what we are trying to do with the example then
39:01:46
it would make perfect sense so let's say that this is our minimum variable this is going to be our maximum variable and
39:01:52
we are going to start iterating in this fashion. So first we identify an open parenthesis which means we are going to
39:01:57
increment the value for both in min and max. So currently both values are going to be one. Once again open parenthesis.
39:02:03
So both values are going to be two and once again open parenthesis both values are going to be three. Now notice what
39:02:08
these values define is that what is the minimum number of open parentheses that we will have to deal with and what is
39:02:15
the maximum number of open parentheses that we have to deal with. So far we haven't encountered any star. So that's
39:02:21
why the numbers are same amongst both of them. Now we encountered a star. So we
39:02:26
can treat the star as either an open parenthesis or a dot or a closed parenthesis.
39:02:32
If it's a one more open parenthesis, then we would have four open parenthesis
39:02:37
that we will need to deal with. And if we treat this as a closed parenthesis
39:02:42
then we will only have to basically deal with one less open parenthesis because
39:02:48
we can basically close these two parenthesis. So in this case this value would become two and let's try to see
39:02:54
this by different examples. So first three values we have as open. Then we
39:02:59
have a star over here. So what are the two possibilities? First possibility is that we create a closed parenthesis. So
39:03:05
in this case this becomes a closed parenthesis. So how many number of open parentheses that we are left to deal with? Two which we are representing over
39:03:12
here. If we treat this as an open parenthesis in this case how many number
39:03:17
of maximum open parenthesis that we will have to deal with four and that we are capturing over here. And this is the
39:03:23
whole logic of the entire solution. So now let's continue moving forward. So once again we identified one more star.
39:03:30
So once again the minimum v variable is going to be decreased by one. So this would become one and maximum variable
39:03:37
would be increased by one. So this would become five. And now we encounter a closing parenthesis. So whenever we
39:03:42
encounter a closing parenthesis basically we are reducing the values at both minimum and maximum values. So this
39:03:49
would become zero and this would become four. Now because we reached to the end of the loop we don't care about this
39:03:55
maximum variable. This maximum variable is only there to keep track of if this goes into negative or not. If it does
39:04:01
goes into the negative which means we can stop immediately and return false. If that is not the case we check the
39:04:07
value of this minimum variable and if because this is zero so in this case we can return true for this one and that
39:04:13
this is a valid string. So this is the whole idea behind the solution. Now if we see timing and space complexity time
39:04:19
complexity is going to be big of n because it's quite straightforward. Space complexity is going to be big of one because apart from using couple of
39:04:25
variables we are not using any extra space. So this is a wonderful solution. And now let's quickly see the coding
39:04:30
solution for this one. So the coding solution is quite straightforward. First we are going to initialize couple of
39:04:36
variables called minimum open and maximum open. This is to keep track of the minimum possible open parenthesis
39:04:42
and maximum possible open parenthesis. Now we are going to start iterating over character by character inside our given
39:04:49
input string s and for every single character we are going to check that if
39:04:54
there's a an open parenthesis then we need to increment both min open and max open. Uh otherwise if it is an closing
39:05:02
parenthesis then we need to decrement both min open and max open and if uh
39:05:07
that is not the case which means we have identified a star value. In this case, we will need to decrement the minimum
39:05:14
open because we are treating it as a closing bracket or an empty string or we need and we need to increment the
39:05:20
maximum open because we are treating it as uh open uh left parenthesis. Now at
39:05:25
any given moment we realize that the max open is less than zero which means we can return false immediately because
39:05:32
there are just way too many uh closing parentheses compared to the subsequent
39:05:38
open parenthesis. Now if that is not the case then we are going to check that at
39:05:43
any given point the if the min open becomes negative then we are simply going to um initial initialize the value
39:05:51
starting from zero. So min open can go into negative but we don't care about that. Now in the end we simply need to
39:05:57
check that if the given min open is equal to zero which means that there are no
39:06:02
minimum possible left open parenthesis. So in this case we can return true saying that the given parentheses string
39:06:08
is valid. So let's try to run this code.
39:06:14
Okay seems like our solution is working as expected. Let's submit this code
39:06:20
and code B it's 100% of all the other solutions which is exceptional. So once again I will be posting the solution in
39:06:27
the GitHub repository that we have created. So you can find it from there.
39:06:41
So now we are going to talk about a very important topic called intervals. It has lot of real life practical applications
39:06:47
because you can imagine a scenario if you are trying to design like Microsoft teams or zoom or any sort of
39:06:54
calendar-like application you you need to be able to find slots where people can book availability. If you are given
39:07:01
bunch of different slots, you should be able to find appropriate intervals that follow certain property. So it is a very
39:07:08
popular topic and I'm going to solve seven questions. This seven question will comprise all the topics that
39:07:16
interval has to offer. So I'm not going deeper into the introduction part. We will start jumping into the actual
39:07:23
interval lead code problems that would cover all the topics. So I hope you find it useful. Hello friends, we are still
39:07:29
not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do meeting rooms lead code problem and this is actually a
39:07:36
lead code premium problem. So uh if you want to know that what are the list of companies that have asked this question
39:07:41
in this in their interviews that comes later in the video and I have provided the timestamp for that you so you can
39:07:46
directly go and check it out. Let's understand the problem statement. Essentially we are given an array of
39:07:52
meetings uh called intervals and we are given start time and an end time for
39:07:57
every single meetings inside this given array. Now we need to determine that if one person can attend all the meetings
39:08:04
or not. So let's try to understand this given uh problem by an example. So over
39:08:09
here we are given three different meeting times and let's try to plot them on this number sequence that we have
39:08:14
created. So first meeting starts from zero time and it lasts until 30 minutes.
39:08:20
Second meeting starts at uh 5 minutes and ends at 10 minutes and third meeting starts at 15 minutes and end at 20
39:08:26
minutes. So over here we can clearly see that there is no way possible for one person to attend all the meetings
39:08:32
because there exist a conflict between this meeting and this meeting and there also exist a conflict between this
39:08:38
meeting and this meeting and this meeting. So because there is an overlap between intervals and essentially that's
39:08:43
what we will have to determine in this problem. So over here we can clearly return false that there does not exist
39:08:50
uh any way possible for one person to attend all the all the different meetings that are given in this interval. Now if we take a look at the
39:08:57
second example and let's try to plot it in u on a number sequence. So over here uh
39:09:05
we can imagine a number sequence like this and over here we are given one meeting that is that starts at 7 and
39:09:12
ends at value number 10 and second meeting starts at two and ends at value number four. So over here we can clearly
39:09:18
see that it's possible for one person to attend this meeting and after that he can attend he or she can attend this
39:09:24
meeting. So in this case we will return true and uh basically that's what we
39:09:29
will need to determine. Now the the tricky part over here is that we will have to determine that how do we
39:09:36
identify that there exist overlap between any two values. So suppose over
39:09:42
here in this example if we are given an another meeting that starts at three and ends at five something like that. Now in
39:09:49
this case can we say that uh does there ex can one person attend all the meetings or not? Well, we can clearly
39:09:55
see that because there is an overlap between these two meetings, one person won't be able to attend all three
39:10:01
meetings and over here we will have to return false. The thing is why we were able to determine that over here there
39:10:07
exists an overlap. Uh so because over here we see that the starting point for
39:10:14
this meeting and ending point for this meeting is from 2 to 4. So that is one interval. And if we look at this one the
39:10:20
starting point from this for this one and this ending point for this one is 3 to 5. So this is 3 to 5. So over here if
39:10:28
we consider this particular um interval we can see that the starting point of
39:10:33
this interval actually falls somewhere between any other interval that already exist.
39:10:40
So at any moment if we determine that the starting point of some interval if it falls between any interval and this
39:10:48
condition is satisfied that two is actually less than three and three is actually less than four which means three falls in between this interval. So
39:10:55
that's why we can determine that there exist an overlap and the moment we identify that there is an overlap over
39:11:00
here we will immediately return false and uh this is how we are going to approach.
39:11:08
Suppose we are given an input like this. Uh the different intervals are given and
39:11:14
this is the number sequence that we are going to use. Now over here essentially if we want to determine that can one
39:11:20
person attend all the meetings we will have to check that whether there exist a conflict or not. So if we look at this
39:11:26
first scenario previously we determined that how to identify an overlap. So if we look at the starting value of this 20
39:11:33
we will have to check that whether this 20 exist in between some intervals. So over here this is 10 to 15. So 20 does
39:11:40
not exist over here. Uh this is 35 to 45. So 20 does not exist over here. And this is 10 to 20. Now this is this
39:11:48
meeting ends at 20 and this meeting starts at 20. So this is also legitimate scenario because 20 is not part of this
39:11:55
interval. So that is why we can determine that okay this meeting is good like the starting point does not have
39:12:02
conflict with any other meetings. Now let's see about this one. So this meeting is from 0 to 15. Right? So does
39:12:08
there exist any conflict between these two between this zero? So 0 does not
39:12:14
exist between this one. Uh 0 also does not exist over here and zero does not exist over here. So we are good. Same
39:12:20
goes for this 35 that 35 does not exist between these two, these one or this one. So we are good. But when we come to
39:12:26
this value number 10, we can clearly see that this 10 actually falls between this
39:12:32
0 to 15 because this condition is satisfied. 0 is less than 10 and 10 is less than 15. So over here we can
39:12:38
clearly see that there exist an overlap between these two elements and we can clearly we can immediately return false.
39:12:45
So this approach would work perfectly fine. But what is the issue with this approach? The issue is that this takes
39:12:51
big of n² time. Why big of n square time? Because remember for every single
39:12:56
element we will have to check all the remaining elements based on the starting point. Uh same goes for this one, same
39:13:02
goes for this one. So that's why we are doing n square work. So this work can
39:13:08
greatly reduce if we just sort the given input uh based on the meeting start
39:13:14
times and let me show you how. So let me clean this up and let me sort this given input.
39:13:21
So now we have the sorted input. Now in the sorted input if you take a look at it we are actually we are actually able
39:13:28
to determine that whether there exist an overlap immediately. How all we need to
39:13:33
do is we'll need to compare the starting point with the ending point of the previous interval. If the starting point
39:13:40
is actually less than the ending point of previous interval we can determine that this meeting actually starts before
39:13:47
the previous meeting ends and immediately we can identify that whether there exist an overlap or not. So this
39:13:53
is basically our solution like in this scenario we can clearly see that the moment we are in the meeting from 0 to
39:14:01
15. So there is a meeting going on from 0 to 15 and before this meeting ends there is there is another meeting that
39:14:08
starts at 10 and last up until 20 minutes mark. So there is an overlap over here and immediately we will return
39:14:14
false in this case. So this approach actually works and uh it is more
39:14:19
efficient than the previous approach we suggested. uh why it is most more efficient because if we calculate the
39:14:24
time complexity the time complexity in this case is going to be big of n log n
39:14:30
for the sorting operation because from this given input first of all we'll have to create a sorted input and once we are
39:14:37
done with that uh if we want to identify the overlap we only need to check any
39:14:42
two adjacent values at any given moment and the moment we reach to the end point and we don't find any issues we can
39:14:49
return true or if we find any issue we can return false before that. So this takes big of n time. So total time
39:14:56
complexity can be considered as big of n log n and uh in terms of space
39:15:01
complexity we are not using any additional space. So we can say that we are only using constant time uh to run
39:15:07
this problem and uh this is the final approach. Now let me show you the list
39:15:13
of com now let me show you the list of companies that have asked this problem and uh if you are not interested you can
39:15:19
directly go to coding. So essentially companies like Amazon, Google, Facebook they have all asked this problem
39:15:24
recently and Microsoft and Wayfair they are also really popular uh well-paying companies that have asked this problem
39:15:31
also companies like Bloomberg, Adobe and uh eBay that one of my dream companies
39:15:36
that I want to join in apart from the original these tech giants.
39:15:44
So first of all we are going to sort the given input based on the start times of the given intervals.
39:15:52
After sorting we will have to iterate over all the sorted intervals and we are going to check that whether there exist
39:15:58
an overlap or not. We are going to check that whether the
39:16:04
uh end point of any meeting is greater than the starting point of next meeting.
39:16:10
If that is the case we are going to return false immediately.
39:16:17
And if this loop ends and we are able to reach to the last element, we are going to return true that there does not exist
39:16:23
an overlap. And now let's try to run this code.
39:16:28
Okay, seems like our code is working. Let's try to submit the code. Okay, our submission works and uh the
39:16:35
code is actually pretty efficient and uh I would be posting this in the comments. It is not too many lines of code and
39:16:40
this problem is very similar to the previous three interval problems that we had we have done. So I would be posting
39:16:47
them in the comments. You can you can check it out from there. Thank you.
39:16:58
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. If there is any question that can get you in the
39:17:05
fang, it's this one that we are going to solve today. Because if you just see that the number
39:17:10
of companies that have asked this question, it's just out of this world. This question has been asked by hundreds
39:17:15
of companies, literally hundreds of times. You can see over here that like Facebook and Amazon, they both have
39:17:21
asked this question recently over 100 times in their interviews. So you can imagine the severity and the importance
39:17:28
of this problem that we are going to solve. Apart from Facebook and Amazon, if we look at the number of companies
39:17:33
that have asked this question, there are companies like Google, Salesforce, Microsoft, Bloomberg, Apple, Uber,
39:17:39
LinkedIn, IBM, uh VMware, Walmart, Tik Tok, Adobe, Twitter, Twitter, uh Bite
39:17:45
Dance and uh then there are companies like Yahoo, PayPal, Wish, Oldman Sachs,
39:17:51
Robin Hood and also Plantier, Square and Netflix. So these are all one of my
39:17:57
dream companies where I want to get a job. That's why I'm making these videos and that's why I made this channel. So I
39:18:03
would be paying my utmost attention. I hope you also enjoy the video. This is a lead code medium problem and
39:18:10
uh it is one of the most liked problems on lead code and that's why a lot of companies likes to ask this problem. So
39:18:16
essentially we are given an array of intervals where every single entry inside the interval mentions that there
39:18:22
exist a start point and an end point of that particular interval. Now we need to iterate over all of the intervals and
39:18:29
then we will need to merge all the overlapping intervals and we need to return an array of nonover overlapping
39:18:35
intervals from this given input and uh that would be our solution. So if we try
39:18:41
to understand this with an example suppose we are given some set of intervals like this. Now let's try to
39:18:47
mention them on this uh number sequence that we have drawn out.
39:18:53
Now over here our aim is to return all the non-over overlapping intervals and
39:18:58
if there exist an overlap we will need to merge those two intervals. So first of all we will have to identify that
39:19:04
what are the those two intervals where we can see an overlap. So essentially if we look at the start values of this
39:19:10
interval. So the start value over here is 1 and 3. And if we look at the start value of the second interval the start
39:19:16
value is actually 2 and six. And over here we can clearly see that there exist an interval amongst these values and
39:19:24
this is these are the two two intervals that are causing an overlap and we will have to merge them. Now the question is
39:19:31
first of all we need to know that why did we why we were able to calculate that there exist an overlap over here
39:19:37
based on the given input like this is a pictorial representation. we can clearly see that why there is an overlap. But in
39:19:43
terms of computer we'll need to dictate some sort of mechanism. So essentially
39:19:49
we can say over here is that at any point if we start iterating over any
39:19:54
number of intervals and if we identify that for those particular intervals if
39:19:59
the starting value so in this case the starting value is actually two. If this starting value falls between any
39:20:08
interval. So because this two currently falls in between this one 2 3 this this
39:20:16
first interval is 1 2 3 and over here the starting value of this new interval actually falls between that those places
39:20:23
and the moment we identify that okay this two falls between this 1 and 3 interval. So we know that okay this uh
39:20:30
interval that starts at 2. So this 2 to 6 is also causing an overlap between
39:20:35
this given input interval and we'll need to merge them. So this would be our condition to identify that at any moment
39:20:41
at any interval we are trying to see that whether it intersects with some other interval or not. What we are going
39:20:47
to check is we are going to see that uh suppose this value is the start value. So we are going to see that this start
39:20:53
value if that meets if that is less if that is greater than whatever the
39:20:59
interval start we are checking and whatever the interval end we are checking for. If this condition is true
39:21:05
we can determine that there exist an overlap and now since we have already identified that there is an overlap uh
39:21:11
we'll need to resolve that. So in order to resolve that how we will resolve that is we will create an interval from this
39:21:17
value number one to value number six. So essentially we are merging both of these intervals and why how what is the
39:21:24
condition we are using to merge these two interval is that we are going to check that okay for the starting point
39:21:29
of the new interval what is the minimum value amongst both the start values. So ina in this case over here the first
39:21:36
start value is one and second start value is two. So the minimum value is actually one. So we create an interval
39:21:42
that starts at position number one and for the end value there is the three and six. So we compare this value three and
39:21:49
we compare the value six and we identify that okay six is greater in this case. So for the end value we are going to
39:21:54
pick the the maximum value amongst two values. So we are going to create a new interval like this that is uh from 1 to
39:22:00
6. And then essentially we have taken care of these two overlapping uh intervals. And for
39:22:07
this one this 8 to 10 and this 15 to 18 these two intervals they are not causing any kind of overlap. So we can just
39:22:14
directly put them as it is inside our uh answer. So in this case if we try to
39:22:20
calculate that what would be our answer? The answer is actually quite simple. The uh answer in this case is going to be an
39:22:27
interval from 1 to 6 and this is the merge interval. Second interval is going to be 8 to 10 and the third interval is
39:22:35
going to be 15 to 18. So this would be our solution and we can simply return
39:22:40
this one. If let's try to understand the same problem with another example that is given over here.
39:22:47
So in the second example we are only given two intervals 1 to 4. So this is one interval 1 to 4. So the question
39:22:54
comes that are they overlapping inteious? And the answer is yes. Why? Because if we see at this value number
39:23:00
four actually four is connecting point for both the intervals. So four is the
39:23:06
ending point for the interval one and it is the starting point for the inter interval number two. So in this case we
39:23:12
actually need to merge these two intervals and we will have to create an interval like this that is from value
39:23:17
number 1 to 5 and again we are going to use the same logic. The logic is going to be that over here the values were 1
39:23:24
to four and over here the values were four to five. So for the starting values we are going to choose the lesser value
39:23:30
and for the ending values we are going to pick the maximum value. So maximum value in the lesser value in this case
39:23:36
is going to be one and maximum value is going to be five. So this would be our intervals and this is the these are all
39:23:41
the scenarios that we need to take care of.
39:23:47
So suppose we are given a custom example like this. Let's see that what what should be the solution. And always
39:23:53
remember that it is really important for any programming interview that you come up with your own custom examples. It
39:23:58
shows that you have the ability to think about all the different kinds of test cases and you can come up some with some
39:24:04
unit test on your own. So over here our aim is to find that all the non-over
39:24:09
overlapping integers. Now for to find all the non-over overlapping integers we already know that what is the condition
39:24:16
that how can we determine that any particular value is actually causing an overlap and the way we can do it is that
39:24:22
by checking the start value and comparing it with that whether it exists somewhere in between uh any given
39:24:29
interval. The question is previous two examples we saw they were already sorted. So they were all the starting
39:24:36
values were already in some in a sorted manner. So that's why it was really easy for us to identify that whether there
39:24:42
exist an overlap or not. But nowhere uh in the sequence we are told that all the
39:24:48
input should be sorted. So that's why thing that makes things a little bit more complicated and let's see that how
39:24:53
it does. So so over here suppose we are given an input 4 to 6. So we can create
39:24:58
an line over here that okay there exists an interval like this from 4 to 6. Now
39:25:03
second one is 11 to 15. So again there is an input like this 11 to 15. Next one
39:25:10
is 7 to 9. So there exists an input from 7 to 9 and this next uh input is 2 to 5.
39:25:16
So we know that there is an overlap but we are going to just draw it over here and the ne next one is 13 to 16. So over
39:25:25
here we can clearly see that there are two places where there exist an uh in overlap but we don't know that yet right
39:25:32
because the input is not sorted and we will have to identify it by ourself. So how we are going to actually identify
39:25:37
well essentially we are going to use the same logic we are going to check that whether the start value falls in between
39:25:44
any of the interval. If it does, we are going to determine that okay that part this so if it does so we know that this
39:25:51
particular interval is in conflict with that interval and then we are going to have to merge it. So let's try to do
39:25:57
that. So over here we are comparing this value number four that is the starting value. First of all we are going to
39:26:02
check that whether four falls between 11 to 15. Well it does not. So we are good with this. Whether four falls between 7
39:26:08
to 9. It does not. So we are good. But over here four actually falls between two to five because the two is actually
39:26:15
less than four and four is actually less than the five. So we know that four actually exist over here which means
39:26:21
there exist a conflict between this and this these two intervals. So we will have to resolve this conflict. How we
39:26:28
are going to resolve this conflict? Well, of course we are going to create a new interval. So starting value is going to be the lesser of both of them. So we
39:26:35
are going to have a starting value that is at two and for the ending value it's going to be greater of both of them. So
39:26:41
the ending value is going to be six. So we are going to create a new interval like this that is from this value number
39:26:47
two to value number six and we are good with this one. So essentially we have merged these two intervals. So we can uh
39:26:53
just simply mention that okay these two are merged or these two are taken care of. So we we don't have to worry about
39:26:58
them anymore. And now we are done with essentially these two intervals right and we have in our answer we already
39:27:06
have this uh this new interval stored. Now let's see that how can we move forward. So again for this 11 to 15
39:27:14
again we will have to repeat the same process. So we check that whether this 11 falls in between some uh interval. So
39:27:21
first of all we we compare this 11 with this four and six. So it does not fall in between. And also remember that
39:27:27
because we are done over here doesn't mean that there could not be any more uh
39:27:33
overlaps that we cannot uh take care of. So we might have to do it. So that's why we are going to compare again all the
39:27:38
values. So 11 does not fall between 4 to 6. 11 does not fall between 7 to 9. 11
39:27:44
does not fall between this 2 to 5 and 11 does not fall between 13 to 16. So so far we are good that okay this 11 to 15
39:27:51
that is okay. We don't have any issue with that. Now we again check for the 7
39:27:56
to 9. So we check that whether the seven falls in between somewhere. So 7 does not fall over here. It does not fall
39:28:02
over here. It does not fall over here. And it does not fall over here. So this 7 to 9 is also good. 2 to 5 we have
39:28:08
already checked. Okay. So this value number two. Two does not fall anywhere. So we are good with this interval as
39:28:14
well. Now again we are at this interval number 13. So for this interval number 13, it does not fall here. But it falls
39:28:22
in this place. So we again have a conflict between this uh these two intervals. So 13 to 16 that is one
39:28:29
interval and second interval is 11 to 15 there exist a conflict. So because there exist a conflict we will have to resolve
39:28:35
that and we can mark that these two as done. So we are going to create a new interval that is 11 and 16 which means
39:28:43
lesser values of the starting values and greater values of the ending values and this would be our new interval. So we
39:28:49
can add this to our answer as well. So this would be uh 11 and 16. This is also
39:28:58
our answer. And now we need to check that amongst these intervals which were the ones that were not part of any
39:29:04
overlapping series. So we know that this particular uh this particular value this
39:29:10
particular value four and six was part of an overlap 2 and five was also part of an overlap. 115 and 1316 they all
39:29:17
were part of overlap which we have taken care of with these two values. So this seven and 9 was not part of any overlap.
39:29:24
So we'll have to add that to our answer as well. And uh we will add the seven and 9 to our answer and this would be
39:29:30
our final answer in this case. Now the thing is we are able to resolve this uh quite easily, right? We are able to
39:29:36
generate the answer. We know all the logic and blah blah blah. We are able to identify the over overlapping condition.
39:29:42
If we calculate the time and space complexity in this case, the time complexity is actually big of n². Why
39:29:48
n²? Because remember that for every single entity we are going to have to check all the remaining elements. Same
39:29:55
goes for this one that for every single entities we are going to have to check for all the other remaining values. So
39:30:01
that causes n² work. The question is can we do something better over here that
39:30:06
rather than using this n square can we bring down the time complexity and the answer is yes.
39:30:15
Okay let's sort this given input. So the sorted result would be
39:30:21
now this is the sorted result. Now we need to identify that whether there exist a conflict or not. So it becomes
39:30:27
really simple what we are going to do is we are always going to check the first value and we are going to compare that
39:30:32
whether the starting point of any value if that is actually less than the ending
39:30:38
point of the previous element. If that is the case, we would be able to identify that there exist a conflict.
39:30:43
And always we are going to start checking from the second value because for the first value, we know that the
39:30:50
first element is already the smallest value. So even if there exist a conflict between first two ent entities, this
39:30:56
first one would always act as a starting point of the new merged uh variable or the new merge interval. So let's try to
39:31:04
do that. And uh over here we will start with the second position. We know that okay this one is four. We compare it
39:31:10
with the last element of the previous interval. So last element of previous interval is five. So we know that
39:31:16
actually four is less than five. In this case we know that there exist an overlap between these two values. Because there
39:31:22
is an overlap we can see that we need to check that we need to take the minimum value among amongst these two. So
39:31:27
minimum value is actually two. So we create a new interval starting at two. And for the ending values we will have
39:31:33
to check the last values. So the ending value in this case would be six. So we
39:31:38
will have a new interval like this. So let's draw a new interval like this on this uh number system. Now we are
39:31:45
already done with these two values. Now we check take a look at this value number seven. So again for the seven we
39:31:51
compare with the last element in this case. So 7 is actually greater than six which means there does not exist a
39:31:57
conflict between these two values. So we can start creating a new interval from seven. And now again for this 11 we are
39:32:04
going to compare it with the last element. So over here this value is 9. So 9 is actually less than 11. Which
39:32:10
means in this case there does not exist a conflict. So 7 to 9 is an interval in its own. We are good with this one. Now
39:32:16
we have calculated this one. Now again over here this is 13 and this is 15. So we know that 13 is actually less than
39:32:23
15. So in this case there there exist a conflict between these two values. So because there exist a conflict we are
39:32:29
going to do the same conflict resolution technique. We are amongst this 11 and 13 we are going to pick the smaller value.
39:32:36
So smaller value is going to be 11. So we pick this one and for this 15 and 16
39:32:41
we are going to pick the greater value. So 16 is the greater value. So again we are going to create an interval like
39:32:47
this that is from 11 to 16. So essentially we have resol we have taken
39:32:53
care of two overlaps that existed between the these two values and these
39:32:58
two values but we are we were able to identify them immediately. Why? Because all we have to do is at any point we
39:33:04
just have to compare one value that was in the previous interval at any given moment. And now over here we can just
39:33:11
simply start iterating over whatever the answer we have found so far. So in this case we can simply return the answer as
39:33:17
uh 2 to 6 7 to 9 and uh 11 to 16 and this would be
39:33:26
our solution. Now if you look at uh look at the solution over here essentially all we had to do is just iterate over
39:33:32
the sorted input once. So basically to generate this answer we are only doing
39:33:38
bigo of n work but the total time complexity in this case is actually going to be big of n login and why n
39:33:46
login because we will have to generate the sorted input from this given original input and that takes n login
39:33:52
time.
39:33:58
First of all, we are going to sort the given input. Okay. After sorting the given input
39:34:04
based on this uh based on their starting values, we are going to uh create a link
39:34:09
list and we are going to uh store answer in this uh link list.
39:34:16
Now we are going to iterate every single interval inside the given input.
39:34:22
So now we are going to check that whether we are at the first position or whether the given interval if that is in
39:34:29
conflict or not. So if that is not in conflict or there does not exist an overlap, we are simply going to add it
39:34:35
to our answer. Okay, if that's not the case, we have detected a conflict and the moment we
39:34:42
detect a conflict, we will have to resolve the conflict. So essentially we are going to add the new interval
39:34:49
that is merged. Okay. And uh after this loop ends
39:34:55
essentially our answer should be in the answer link list. So we can return that. But in this case we need to return a
39:35:02
two-dimensional array. So we will convert our uh answer uh list to a 2D 2D
39:35:08
array. Okay. Let's try to run this code.
39:35:22
Seems like our solution is working. Let's try to submit this code.
39:35:28
Okay, our solution works pretty efficiently. I would be posting the solution in the
39:35:34
comments. You can check it out from there.
39:35:45
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do a very interesting lead
39:35:52
code problem. Interest interval. And if you see the number of companies that have asked this question, it's really
39:35:57
amazing. Uh the companies like Google, LinkedIn, Amazon, Robin Hood, Facebook, Uber, Apple, Twitter, Microsoft, Service
39:36:04
Now, Bloomberg and Goldman Sachs. like these are if you see the description of my channel, these are my dream companies
39:36:11
that I want to get a job of. So that's why I'm doing these questions and I'm paying my utmost attention. I hope you
39:36:16
also enjoy the video. So this is a lead code medium problem
39:36:22
and essentially we are given an array of non-over overlapping intervals. This is a multi-d dimensional array. It's a 2D
39:36:29
array and at any given cell essentially we are given the value like start and
39:36:34
end which indicates that there exist an interval between those times. Now our
39:36:39
aim is that we need to insert a new interval into the list into the array of intervals that we are already given and
39:36:46
we need to we need to maintain this nonover overlapping uh quality of the
39:36:51
intervals. So if we try to understand this this with an example uh suppose over here we are given a set of
39:36:58
intervals like 1 3 6 9. So we are given an interval like this 1 2 3 this is
39:37:04
already given and we are also given another interval like 6 to 9
39:37:10
and we need to insert a new interval called 2 to 5. So if I draw it on paper
39:37:16
it would be something like this. So two would fall over here and five would fall over here. And this is the new interval
39:37:23
that we are trying to insert in this original existing interval. So how can we insert this new interval? Well, the
39:37:30
answer is actually simple. Essentially what we are going to create a new interval is that we will start an
39:37:36
interval at position number one. Then from one we will have an interval all
39:37:42
the way up until the position number five. And then we will have another interval from position number six and
39:37:48
all the way to position number nine. And this would be the two intervals that we will have to take care of. Now the thing
39:37:55
is in this problem we can clearly uh identify that why did we come up with
39:38:00
this approach because we wanted to make sure that we do not we do not have any
39:38:06
overlapping intervals. So that is why when we found out that this is the existing interval and this is the new
39:38:12
interval that we are trying to achieve. If we wanted to insert this one, there exists an overlap between these
39:38:19
positions between this two and three. So that's why because there was an overlap, we actually chose to merge these two
39:38:26
intervals and we created a new interval like this. And for this one, this had no
39:38:32
concern with the existing uh new with the coming coming of new interval. So
39:38:37
that's why we left it as it is. So let's see that what could be the different uh uh approaches we can take. what could be
39:38:44
the different scenarios and how we need to behave in any single scenario of them
39:38:49
and essentially that would be our solution. So first of all if suppose we
39:38:54
are given a number series like this and we are given a list of uh intervals like this that there exist an interval
39:39:00
between this value 2 to 4 there exist another interval between this value 8 to 10 and 13 to 15. Now we let's see that
39:39:10
where different set of intervals can be entered. So suppose first of all we are
39:39:15
given an interval like this that is not overlapping with or that is not in conflict with any existing interval. So
39:39:23
let's see that what would be the scenario in that that case. Suppose we are given an interval like this that
39:39:28
from 0 to 1 we are given an interval like this. Now if we see this new interval, it has no sort of conflict
39:39:36
with any of the existing intervals. If we wanted to add this to our uh array of intervals, it would be just pretty
39:39:42
simple. We simply create a new interval like this 0 to 1 and then return whatever all these values are and this
39:39:50
would be our answer. So we we should be we would be done in this case. There wouldn't be any issue. But suppose
39:39:57
if this is not at the first or at the beginning of the intervals. If this is at the end of an intervals. So suppose
39:40:04
this particular uh new interval that we are trying to enter. Suppose we are given some interval like this
39:40:12
that uh from 16 to 17 we are given an interval. So suppose we are given interval from 16 to 17 something like
39:40:20
this. Now in this case what would be the approach? uh essentially we would be doing the same thing. What we would be
39:40:26
doing is we would be transferring this interval on top of whatever the existing intervals we got and how we are going to
39:40:33
do it as basically we are going to start traversing towards the original given
39:40:38
input. We are going to see that okay where is the starting point of this new interval and where this new interval can
39:40:46
fit inside the existing set of intervals that we have. Now in order to check that
39:40:52
essentially what would be helpful? It would be helpful if we had a sorted uh set of intervals and in this scenario
39:40:59
all the intervals that we are given they are already sorted. So that is why which works in our favor. So which means it
39:41:06
becomes really easy for understand that where this new interval we wanted to uh
39:41:11
shift into and in this case uh so we will start traversing we will first see that okay this is the value two this is
39:41:17
a this is 16 we don't care so we move forward uh again we are done with this interval now what is the next start
39:41:23
point of this interval this is 8 and this is 10 and this is 16 so again it
39:41:28
doesn't matter there is no overlap so we can put this in the answer again this is 15 this is this is 13 this is 15 and
39:41:34
this is 16. So again there is no overlap. So we can put this in the answer as well. And then we find out
39:41:41
that after 15 there are no intervals and we need to enter this new interval uh interval 16 and 17. So we simply add it
39:41:49
over here from 16 to 17 and we add this to our array of answers as well and we
39:41:55
return these four as new new set of intervals. Now suppose somewhere in the
39:42:01
m rather than this one this these are like easy scenarios where we are given at the beginning or at the end. Suppose
39:42:08
we are given something somewhere in the middle. So suppose we are given a new interval that we have to take care of uh
39:42:15
something like this that it is from 5 to 7. This is the new interval that we are
39:42:20
trying to insert. What should be the approach in this case? Again we are going to repeat the same case over here.
39:42:25
This this is the value five and 7. And now what we are going to do is we will start iterating over this given input.
39:42:31
We will see that okay first value is two and uh the end of this this interval is
39:42:37
at four. So this is 2 and four and the new interval starting point is five
39:42:42
which means there is no conflict so far. So we would add this to our set of answers. Now from this four we reach at
39:42:49
this five and at this five is the starting point of this new interval. So
39:42:54
we check in our original set of intervals that from 5 to 7 does there exist any conflict. So from 5 to 7
39:43:02
actually there is no conflict in our original interval. So if there is no conflict, we simply add a new interval
39:43:10
over here from 5 to 7. Add it to our list of answers. And because we have reached the end of our new interval,
39:43:17
right? We are we have reached the end of our new interval. Which means what this dictate dictates is that
39:43:24
from this point forward there cannot be any existing interval that could be
39:43:30
causing any sort of overlap with this uh with the arrival of this new interval. So whatever the answer or whatever the
39:43:37
list of intervals we are given beyond this point once we have already entered this new interval we can simply add
39:43:43
these to our answer array and this would be our solution. So this would make our lives very easy and that is how we we
39:43:51
would be able to handle this scenario as well. Right now the so far the all the
39:43:57
three scenarios we saw we entered the value at the beginning at the end or somewhere in the middle. But in all the
39:44:03
cases there was no conflict between existing intervals with the new with the arrival of new intervals. Now suppose
39:44:11
the new interval that we are trying to enter uh that new interval is something like 3 to 8. Suppose it's something like
39:44:19
this that now we need to take care of the scenario where we are handling this new interval and which is from 3 to 8.
39:44:26
So what should be the approach in this case? Well the approach is actually quite simple. Uh we will start iterating
39:44:32
over our input. We will find all the intervals. So first we find that what is the start point of this interval. So the
39:44:39
start point of this interval is two and what is the end point of this interval? The end point of this interval is four.
39:44:45
Now what is the and every time with the end interval we are going to compare the
39:44:51
start interval of the new uh new inter new new interval that we are trying to insert. So the start interval of this
39:44:57
one is three and this one is four which means that we know that we will have to enter this three over here and there
39:45:04
exist a conflict. Now since we have identified a conflicting scenario what should be our approach? Well, our
39:45:10
approach should be simple that we are going to take a look at this particular interval and we are going to take a look
39:45:16
at this particular interval. Now, there exist a conflict because there exists a conflict, we are going to check the
39:45:22
starting points of both the intervals. Now, in terms of starting points of both intervals, this one is smaller than this
39:45:28
one. So whatever is the smaller we are going to treat this as the starting
39:45:33
point of this new interval that we are trying to enter because there exist an overlap uh amongst these values. So we
39:45:40
are taking care of the overlap. So that's why this would be our starting point. This would be the start of this
39:45:45
new interval and we are going to drag this new interval up until the end of this point. So up until the end of this
39:45:52
point when we come we find out that it ex it comes up until all the way to value number eight. Now in this scenario
39:45:59
we did not had anything in the middle but if we did had anything in the middle that would have been merged by this new
39:46:04
interval right. But thing is even when we come at this position number eight we see that actually the position number
39:46:10
eight is start of another interval. So which is this one. So if it is start of this interval we cannot just treat this
39:46:18
as a separate interval. I mean what I'm trying to say is we cannot have an interval like from 2 to 8 is one
39:46:24
interval and from 8 to 10 another interval because this 8 is actually a
39:46:29
conflicting point and it is a connect because it is a connecting point these two intervals also needs to be merged.
39:46:35
So because this 8 is a connecting point, we are going to merge this interval with
39:46:41
this uh new interval that we are trying to create. And essentially this interval
39:46:46
from 8 to 10 will also be dissolved by this new interval. And we would have an
39:46:52
answer like this in this scenario that uh we would have a new newly created
39:46:57
interval from 2 to 10. This would be for one interval where we have and this would be another interval because
39:47:02
remember now we have already entered this one which means all the values beyond this point are not part of our
39:47:08
concern we concern. We can simply add it to our uh list and in this scenario the
39:47:14
second interval would be uh from 13 to 15 and this would be our answer that we
39:47:19
are going to return. So this is one conflicting scenario and uh I mentioned
39:47:24
that how we are going to tackle it. So essentially the different test cases in this case we we can have is that we can
39:47:31
either have a scenario where the item lies somewhere between beginning or at
39:47:36
the end where it is not conflicting with anyone or it can be existing somewhere in the middle where it is not existing
39:47:42
not overlapping with any other interval or it can be a case where it conflicts
39:47:49
with some intervals with one interval or more than one intervals. In either scenario what we are going to do is the
39:47:56
moment we find that there exist a conflict we are going to see that what is the start point what is the lower
39:48:01
value amongst these two. So because the lower value is two we are going to start this new interval starting from the
39:48:07
position number two. Okay. Now for the end position again we are going to do the same thing. We are going to check
39:48:13
that what is the end position of this existing interval and what is the end position of this new interval. And in
39:48:19
the end position we will have to uh check the maximum value because the interval we are trying to create should
39:48:26
be the size of biggest interval that we could create which is not overlapping with any other interval. So that's why
39:48:33
we would have an interval that is maximum amongst these two ending values. So these two ending values the value is
39:48:40
8. So we would have an interval from 2 to 8 so far. But thing is this is not the end yet because when we come at this
39:48:46
eight we will still have to check for the conflicting scenario. So over here we have we would have the starting we
39:48:54
would have two intervals like this and in the two intervals we have the eight
39:48:59
value as the value number eight as common. So we are going to merge these two as well. And in this case we are
39:49:06
going to choose the biggest value we can find as 10. And we are actually rather
39:49:12
than having an interval from 2 to 8, we would actually have an interval from 2 to 10. And this is the critical part to
39:49:20
understand. And this is basically our solution. Essentially, we are using the greedy approach. But this is all we
39:49:26
don't need to do anything else. And if we calculate the time and space complexity, the time complexity in this
39:49:31
case would be actually big of n because at at any point for this new interval,
39:49:37
we would need to find that what what should be the entry point of this new interval and then we will check for the
39:49:43
conflicting scenario. If there exist a conflict scenario, we will find a way to put it there. If there does not exist
39:49:48
any conflicting scenario, well, good for us. uh in terms of space complexity well for the space complexity it would also
39:49:54
be big of n because we will have to create a new array of list of intervals that we are going to return. So we will
39:50:01
have to create a new two-dimensional array something like this in this scenario from where the answer would be
39:50:07
2 to 10 and uh 13 to 15. So this would be our new array that we are creating
39:50:13
and we would be returning that. So that's why that explains the space complexity and uh yeah this would be the
39:50:21
solution. Now the question is where can you use these kinds of approaches like what is the point of having this
39:50:27
question in at the first place and actually this is a very interesting question. It has lot of practical applications. practical applications is
39:50:33
like suppose you are trying to design an an app where you need to maintain some sort of calendar
39:50:40
or we you need to maintain scheduling. So
39:50:46
the and these are very practical very real life applications uh Google mail,
39:50:51
outlook all the companies they all use this mechanism they all use this mechanism. So if we know that where we
39:50:58
need to insert an interval where we are not creating any conflict it could be a conflict between shifts of two employees
39:51:04
working for a factory or it could be the interval between two trains going through a station. So like yeah these
39:51:11
are real life practical exams and that's why the that justifies the number of companies that are asking this question.
39:51:21
So first of all we are going to initialize some variables and uh we are going to create a new start and new end
39:51:28
for the given uh new interval. We are also going to create two pointers
39:51:34
left and right and left would be at the zero position inside the given intervals
39:51:39
and right would be the last uh the size of the given intervals.
39:51:45
We are also going to create a link list to store all the output and then we are going to convert it into the array.
39:51:52
So now first of all we are going to add all the non-over overlapping intervals that come before the new start. So we
39:52:00
are going to create a while loop. Okay. Now inside our given list we will
39:52:06
need to add the new interval. So in order to add the new interval we will have to check two. There could be two
39:52:12
possibilities. There might be an overlap or there could not be an overlap. So we'll have to take care of both of them.
39:52:18
So first we are going to create a parameter called interval and we are
39:52:23
going to uh store all the value inside this parameter. Now we are going to
39:52:29
check the condition that if the current uh position where we need to insert the
39:52:35
new interval does there exist an overlap or not. So if there is no overlap we can just simply add the new interval.
39:52:45
So if that's the case we can just simply add the new interval.
39:52:50
If that is not the case which means there exist an overlap. So if there is an overlap we will have to first of all
39:52:57
check that what entry we like what should be the uh starting point and
39:53:02
ending point of the overlapping character and that we can define by choosing the minimum out of the starting
39:53:09
values or the maximum out of ending values. So first of all we are going to
39:53:14
add the last value we have in uh our uh link list inside this new interval
39:53:20
variable that we created.
39:53:26
And now we are going to check that what should be the end point
39:53:34
and we would add the new entry to our link uh link list.
39:53:43
Okay, now we might have to merge all the elements that are after uh that came
39:53:50
because we added this new interval. So we will take care of the merge scenario
39:53:57
and if there exist an interval we will do the same thing that we did before. So
39:54:03
essentially we can just repeat this process.
39:54:08
Uh yeah, after this loop runs, uh we should have everything stored inside the link list. So we can return the link
39:54:15
list, but we will have to convert the link list to an uh array.
39:54:22
This should be our answer. Let's try to run the code. It seems like our solution
39:54:27
is working. Let's try to submit this code. Oh,
39:54:34
we will have to check for the this end variable here.
39:54:42
So that's why.
39:54:49
Okay, looks like our solution is working and it's actually pretty fast compared to a lot of other solutions and even in
39:54:55
terms of space complexity, we are also saving a lot of time, a lot of space as well. So I would be posting this in the
39:55:01
comments. So you can check it out from there.
39:55:10
Hello friends, we are still not employed by a fang company. So let's not stop late coding till we get there. Today we are going to do non-over overlapping
39:55:16
intervals problem. And this problem is actually very similar to merge interval problems and insert interval problems. I
39:55:23
have solved both of these problems and I will be posting their links in the description so you can check it out from there. Like though this problem seems
39:55:30
like it has not been asked by many companies actually this can be a very interesting uh post question after these
39:55:38
two interview questions. So uh usually like all the interval problems they are
39:55:44
done in sync and even for this particular problem if we see it has been asked by tech giants like Facebook,
39:55:50
Amazon, Microsoft, Bloomberg, Apple, Oracle, Google, Byons which is Tik Tok and Snapchat and these are my dream
39:55:58
companies. So I'm paying my utmost attention. I hope you also enjoy the video.
39:56:03
This is a lead code medium problem and we are basically given an array of intervals where every single entry has a
39:56:10
starting point and an ending point that represents that particular interval. Now our aim is in this problem is that we
39:56:17
need to return that how many minimum numbers of intervals that if we remove
39:56:23
uh from this given original input if we remove those then the remaining result
39:56:28
should be uh such that all the intervals becomes non-over overlapping. So we need
39:56:34
to return the number of intervals that we need to remove. So let's try to understand this problem with an example
39:56:40
that is given over here. And over here we are given some set of intervals and let's try to plot them on this given uh
39:56:48
number series and see that what would be the answer. Okay. So after plotting all of these our
39:56:56
aim is to return our aim is to see that okay if there exist an overlap inside this given interval uh we need to return
39:57:04
the minimum number of intervals such that all the remaining intervals becomes non-over overlapping. So over here we
39:57:10
can clearly see that okay there exist an overlap between these points and the
39:57:16
overlap is actually mainly caused by uh because of this particular interval and
39:57:22
these two intervals. So our aim is to remove the minimum number of intervals
39:57:27
that uh that basically allows all the remaining intervals to become non-over overlapping. So in this case if we
39:57:34
simply remove uh this particular interval that starts at position number
39:57:39
one and ends at position number three this big one. So if we get rid of this particular big big interval we will have
39:57:46
a result where all the intervals they are actually not in collision with each other and they are not overlapping with
39:57:51
each other. Over here we can see that they uh they actually connect at some point but that is not an overlap. Like I
39:57:58
know that in previous questions we used to consider this as an overlap but you can confirm this with your interviewer
39:58:03
that with what approach they want to go. So in this case we only get rid of this one interval that was existing and
39:58:09
because we get rid of one we will return one that in this given input. If we simply remove one interval we would we
39:58:16
can determine that okay there exist uh one interval such that uh if we remove
39:58:22
that then all the other intervals becomes non-over overlapping.
39:58:30
Now to generate the optimal solution the main thing is that we will have to determine that whether there exists an
39:58:35
overlap inside the given interval or not. Now the previous examples we saw the input was already sorted but in the
39:58:42
problem statement it is nowhere written that the input should be sorted. So input could be something like this where
39:58:48
everything is different value. Now the thing is first of all over here we need to determine that what are the intervals
39:58:53
that are actually causing the overlap and then we can determine that what which one should be removed and what not
39:58:59
blah blah blah what should be the strategy for that. Now the thing is uh if we plot these uh this given input on
39:59:05
side on a number system we will get a result like this over here we can clearly see that there exist a conflict
39:59:12
between uh these two intervals uh which is represented over here. The thing is how we were able to identify that there
39:59:18
exist a conflict. We were able to identify it because the starting point of this particular uh interval was
39:59:25
actually falling between uh the two values of some already existing interval. So that is the condition we
39:59:31
will have to determine if we want to find that whether there exist an overlap or not. So over here suppose we get at
39:59:38
value number five and we want to check that whether five has an over has an overlap anywhere. So five we will have
39:59:44
to check all the other intervals. So five does not exist between this 2 to 4. So there is no overlap with this one. It
39:59:50
also does not exist between 8 to 9. So there is no overlap. And it does not exist between 1 and 3. So that's why
39:59:55
there is no overlap. So now we are we are say that okay this five 57 has no overlap with any other uh interval. Now
40:00:02
we check for this value number 2 to 4. So again we check the starting point for the value number two. So value number
40:00:08
two does not fall between 8 to 9. So there is no overlap. But two actually falls between this 1 2 3 because 1 is
40:00:14
actually less than the value two and two is actually less than the value number three. So which means two falls between
40:00:20
this interval. So that's why the interval 2 to 4 and 1 2 3 are in between
40:00:26
uh an overlap and then we will have to take care of that scenario. Now do you see a problem with this one and the
40:00:31
problem is that I can see is that for every single value we will have to check all the other remaining values that
40:00:38
whether there exist an overlap or not. And that actually causes bigo of n square time and this is unnecessary work
40:00:46
like even just to determine that whether there exists an overlap or not we are actually doing bigo of n square work
40:00:51
which is like pointless. Uh there there exist a better approach and the better approach is uh that if we sort the given
40:00:59
input and then we sort them based on their starting values things becomes lot
40:01:05
a lot easier. So let's see that what should be the sorted array.
40:01:10
Now we have sorted this given original set of intervals and now we have all the values sorted. So now if we see if we
40:01:17
want to identify that whether there exists an overlap all we need to do is we just need to compare any two adjacent
40:01:24
values and the moment we compare any two adjacent values we can directly tell that whether there exist a conflict
40:01:29
between them or not. How can we tell them is that we only need to check that whether the starting point of any uh
40:01:36
second interval compared to its previous interval if that is smaller then we know that there
40:01:43
exists a conflict. So in this case we can say that between this 1 and 3 and 2 and four there exists a conflict because
40:01:48
this particular interval ends at value number three and this particular interval starts at value number two. So
40:01:53
that's why there is a conflict. Meanwhile, if we see over here, this particular interval ends at value ends
40:02:00
at value number four and this one starts at value number five. So that's why there is no conflict. So this is a very
40:02:06
easy way for us to determine that whether there exists a conflict or not. And if we see in terms of time
40:02:11
complexity, the time complexity for the sorted operation uh takes only big of n
40:02:16
log n which is a big improvement compared to the previous time complexity for this one which was big of n². Okay.
40:02:23
Now we have determined that how to identify overlap. The question is that how to find that what should be the most
40:02:31
number of nodes that we will have to remove and uh what should be the strategy for it. So essentially there
40:02:38
can be three different scenarios at any given moment. The first scenario is that between two intervals there does not
40:02:44
exist an overlap. So if there does not exist an overlap there is no need for removal. So we don't need to remove at
40:02:50
anything. So we are good in this case. This is like the most beautiful thing. The second scenario is that we are given
40:02:57
one interval that is clearly bigger compared to the second interval. So essentially we can say that the second
40:03:03
the second interval is actually subset of this given bigger interval. So in this case things actually becomes pretty
40:03:09
easy for us. All we need to do is that we simply need to remove the bigger interval because there is a conflict
40:03:17
between these two intervals right now which we can see. But there could be possib possibility that there might
40:03:23
exist some other interval something like this. So say in this scenario if we got rid of this interval we still have to we
40:03:30
will still find ourself to be having conflict between these two intervals and again in order to resolve that we'll
40:03:37
have to remove this one as well but rather doing this suppose in this scenario we only had uh two intervals
40:03:44
like this and originally if we just got rid of this bigger interval then immediately even though there exist
40:03:50
another interval somewhere down which was actually causing an overlap between this original interval still we would we
40:03:58
will have to perform less remove operations. So that is why uh the
40:04:03
strategy should be that always remove the bigger interval. Now the question comes in scenario like this where the
40:04:09
starting point of one interval is actually falling before and the starting point of second interval actually falls
40:04:15
somewhere in between. So what should be our approach in this scenario and in this scenario as well what I'm
40:04:21
suggesting is that we remove the interval that has the longer end point
40:04:28
essentially if we at any point identifies ourself in this kind of scenario our strategy should be to
40:04:35
remove the end to remove the interval with the end point that is greater. So
40:04:41
suppose we consider that uh the starting point for this interval is actually 1 2 3 and suppose we consider that uh
40:04:49
starting point for this interval is 2 to 4. So in this scenario the the strategy
40:04:55
we are going to use is that we are always going to remove the interval 2 to 4. Why? Because the we are going to
40:05:01
compare the end values and whichever interval has the greater end value we will decide to remove that particular
40:05:07
interval. So essentially we are using a graded approach. But by using this graded approach what we are going to do
40:05:13
is that over here we know that for this particular case for this particular interval we only had an interval that
40:05:20
was causing an overlap over here. But again the same thing could happen that we might have another interval like this
40:05:26
where this particular interval was causing an overlap between this and this and also this. So immediately remember
40:05:34
our input is sorted. So we are coming from left to right inside the number sequence. So the moment we identify that
40:05:41
whatever has the greater end point if we decide to remove that. So even over here
40:05:46
we already got rid of this one. So even over here if there exist another interval that comes after this 1 2 3
40:05:53
still it would not be in overlap with this 1 2 3 and we will have to do less remove operation and this would be our
40:06:01
ideal approach. If we calculate the time and space complexity, basically the time complexity in this case is going to be
40:06:07
big of n log n. Uh and why n login? Essentially
40:06:13
doing this interval converting this interval from a normal input to sorted
40:06:18
input takes n login and time and then after that once we have this input given
40:06:23
essentially all we need to do is just we have to iterate over the given input once because it is already sorted and
40:06:29
then we can perform the remove operation and we can count the number of times we removed any interval. So that this
40:06:36
second part takes big of n time. So total work we are doing is actually big of n login plus big of n but in general
40:06:44
we can write this as big of n log n and in terms of space complexity we are not
40:06:49
using anything extra. So we can just say that it's a constant time space complexity at most at most we are just
40:06:56
going to use couple of extra uh variables.
40:07:03
So first of all we are going to check that if the given uh intervals is empty. So we are going to return uh zero.
40:07:11
Okay. If the that's not the case, we will have to sort the given input and we are going to sort the given input based
40:07:17
on uh the starting values.
40:07:23
Okay. After the sorting, we are going to initialize couple of variables. So we are going to keep an keep a variable
40:07:29
called previous to keep track of the previous element and uh we will initialize it to zero. We are also going
40:07:36
to have a variable called count to keep track of the number of elements that we will have to remove. So we are also
40:07:43
going to initialize it to zero. And now we are going to run a for loop that runs over the given sorted input. And over
40:07:50
here we are going to start it as int i is equal to 1 because we already have the previous value as zero for the
40:07:57
comparison. And remember that because the input is sorted at any given moment we are only comparing two adjacent
40:08:03
elements inside the given interval. So first of all we are going to check that if there exist an overlap between
40:08:10
two adjacent elements and if there exist an overlap we are going to check that which element is having the greater end
40:08:18
value. So we will update the previous counter based on that and if there exist an overlap we are going to increase our
40:08:25
count. This second if condition dictates that
40:08:32
the if the previous uh interval is actually greater than the current interval we are at we will have to
40:08:39
update the previous counter to next element. And in any case we are going to increment our counter count variable.
40:08:49
And if this is not the case uh essentially we have found that between two adjacent intervals there does not
40:08:55
exist uh any overlap. So we are going to increase our value of our previous uh
40:09:03
count previous variable to the current I so that we can use it for further uh
40:09:09
implementation. And uh once we are done with this loop, essentially this count
40:09:14
variable should have our answer. So we can simply return the count variable. And uh this should be our solution.
40:09:22
Let's try to run the code. Okay, seems like our solution is
40:09:27
working. Let's try to submit the code. Okay, our solution is working as
40:09:33
expected and uh it's actually pretty efficient in terms of memory usage and even in terms of time complexity it's
40:09:39
not that bad compared to other solutions. I would be posting this in the comments and you can check it out from there. We are not going to stop
40:09:45
till we get into fang and uh see you in see you next time.
40:09:56
Okay, now let's just quickly go through this remove interval problem. uh this is a lead code 1272 number problem and this
40:10:02
is actually a lead code premium problem. So that is why I decided to solve this problem because I know not many people
40:10:08
can afford the the lead code premium subscription and since I already have it I want to make the most use out of it.
40:10:14
This is a lead code medium problem and in this problem basically if you want you can read this whole statement but
40:10:19
I'm just going to explain you that what it is asking us to solve. uh we are simply given uh an array of intervals
40:10:26
that defines some intervals that we are already given and these are already non-over overlapping intervals that is
40:10:32
good in our favor. We are also given a new interval that we need to remove. Which means if we remove this new
40:10:38
interval, all the intervals that it overlaps, they needs to be removed from this original input list. And then we
40:10:45
only need to return a new list of arrays or new array list that contains all the
40:10:52
intervals that are not part of this to be removed part. And that is the answer
40:10:57
we need to return. So let's just try to understand this with an example. Uh suppose uh again just like this we are
40:11:04
given an interval that like looks like this and uh let's just give values 1 3
40:11:09
and then 5 7 and then 9 11 okay and then we are being asked to remove an interval
40:11:14
that looks like this. This one the value is 2 to let's just say six. Okay. This is what we need to remove which means we
40:11:21
can still keep this portion but we cannot keep this portion. This we will
40:11:27
have to get rid of and even until this portion everything needs to be get uh
40:11:33
getting rid of but this portion we can still keep. So the answer in this case is going to be that first we will have
40:11:40
an interval that is 1 to2 then we won't have any interval until the value six but after the value six there exists an
40:11:47
interval between values 6 and 7. So again between 6 to 7 there is going to be a new interval and then this 9 to 11
40:11:54
is going to left untouched because it was not part of this 6 to 11. So what
40:12:00
the simplest solution we can do is and in my opinion this should have been a lead code easy problem not medium
40:12:06
problem but uh anyways lead code has their own ways to decide. What we can simply do is whenever we are given an
40:12:12
input and we are also given the interval we are trying to remove. So if we just take a look at the same example again uh
40:12:19
basically what we can do is that simply we can check for every single interval
40:12:26
that we iterate over to see whether it conflicts with this new interval that we
40:12:32
are trying to get rid of. So in the first place we check okay this value is 1 2 3 and the value that we are trying
40:12:38
to get rid of starts at value number three which means that there exist an overlap between these two intervals. So
40:12:45
because there exist an overlap we will have to do something and what we are going to do is we are only going to pick
40:12:51
the values between this 1 and two. So between these two starting values we are
40:12:57
going to create a new interval and store it in in our answer. So 1 to2 is going to be the new interval. Then this one
40:13:05
this part we don't care. Okay. Now we are on the next interval. Again for the next interval we are going to check that
40:13:12
does its ending value is greater than the ending value of the part we are
40:13:17
trying to remove. If that is the case which means there is a possibility that this interval will have some value that
40:13:23
we can add in the answer. Suppose over here if we had one more interval that looks like this. Okay, I'm just giving
40:13:29
giving you an example. Then this interval has to be removed completely
40:13:35
because both of their starting and ending value falls between these two portions. So then we can we can't do
40:13:41
anything in this case which means that this uh interval is no use for us. So we
40:13:46
will simply skip to the next one. But in this case since this interval already has a value that is greater than the
40:13:52
ending value of the part we are trying to get rid of. So then the value difference between the part we are
40:13:59
trying to get rid of and the ending of this current variable so that is 6 to 7 that would be stored in our answer. So 6
40:14:06
and 7 would be stored and then all the other values. So in this case 9 and 11 will be left untouched and we can add it
40:14:12
to the answer and this is the whole solution. Now if we see time complexity in this case the time complexity is
40:14:18
simply going to be big of n because we might have to iterate over every single value inside the given input. And in
40:14:25
terms of space complexity well this is debatable. You can argue with your interviewer since in this case we are
40:14:31
explicitly told to create a new list and return that we are just simply creating a new array list and then we are adding
40:14:38
all the solutions to that. So in this case we can mark the space complexity as constant. But if we are not being asked
40:14:44
and still you are using a new array list then it could be considered as big of n. So you can uh discuss with your
40:14:50
interviewer on how you want to treat the space complexity as and this is the whole solution. Now let's move I I'll
40:14:56
just show you the coding part for this remove interval problem. Okay. So for the coding solution for
40:15:03
this remove interval part uh this is the input we are given. Basically we are given the set of intervals and we are
40:15:09
also given a new interval that needs to be removed. uh first we are going to initialize a new list where we are going
40:15:14
to store the result uh that does not contain any interval that is uh to be removed. Then we are going to iterate
40:15:20
over the given input of intervals. First we are going to check that if we find all the intervals that does not have any
40:15:27
sort of overlap before this to be removed and after this to be removed we
40:15:32
can simply add it to our this new result list we created as it is. No issues with that. However, if we find that there
40:15:39
exist an overlap, in that case we will have to pick the smaller portion. So
40:15:44
between the starting values, we are going to pick the in we are going to create a new interval that is made out
40:15:52
of the the beginning values of these two interval values. And even for the ending
40:15:58
portion, we are again going to repeat the same process that to find the interval that is made out of the two
40:16:05
ending values differences. nothing more than that. And after that, after this
40:16:10
loop ends, basically we would have our result populated inside this new list we have created and we can simply return
40:16:16
that. Let's try to run this code. Okay, seems like our solution is working
40:16:22
as expected. Let's submit this code. And our code runs pretty efficiently in terms of time and space complexity. So
40:16:29
you can see how interval problems are behaving. I just showed you this solution because I haven't solved this
40:16:35
before and I just thought that you at least get some idea on how these interval items are being done.
40:16:49
Hello friends, we are still not employed by a fang company. So let's not solve lead code in we get there. Today we are going to do a lead code premium problem
40:16:55
and uh you can clearly see that this has been one of the most popular lead code premium problems. This has been asked in
40:17:02
companies that companies like Amazon, Facebook, Google, Bloomberg, Microsoft, Oracle, Walmart, Uber, Twitter, Apple,
40:17:10
Goldman Sachs, Tik Tok and by Dance and also some other companies like eBay,
40:17:15
Adobe, Swiggy. Uh they all have also asked this question uh fairly recently.
40:17:20
So my aim you all know that I want to get a job at any top tier fang company
40:17:25
and that's why I'm making these videos. So I am paying my utmost attention and I hope you also enjoy the video. Lead code
40:17:33
medium problem and it is one of the most popular problems on lead code. If you see the like to dislike ratio also the
40:17:39
name is meeting rooms 2. So basically it is the next version of the original problem meeting rooms that I have
40:17:46
already solved over here. So you can check it out from there. Now in this given problem we are basically given an
40:17:52
array of meeting times called intervals and we are given a start value and an end value and obviously start value is
40:17:59
always going to come before the end value like as it should be. Now we need to say that based on the given uh number
40:18:06
of uh meetings how many number of minimum conference rooms we are required
40:18:12
so that all the meetings can be accommodated and we know that for any single meeting we need at least one
40:18:19
conference room and when that meeting ends that conference room can be used for some other meeting. So suppose uh
40:18:25
say for one example we have a meeting that starts at uh at five uh and ends at
40:18:31
15 minutes and we have another meeting that starts at let's say uh 17 minutes
40:18:36
and ends at 27 minutes something like that. So in this case if we only have one conference room we are still good.
40:18:43
Why? Because first of all this meeting will take place. All the attendees will attend this meeting. At 15 this meeting
40:18:50
is going to end and then they are going to leave away from this uh meeting and then these new people are going to
40:18:56
attend the meeting in the same conference room. So in this case we can clearly determine that okay with one conference room we are we are we are
40:19:04
sufficient to complete all the meetings. Now but problem comes when say for an
40:19:09
example we have a meeting that starts at zero and ends at 30 minutes. Uh I'm
40:19:14
using this original example that is given. So suppose we have we have a meeting that starts at 0 minute and ends
40:19:20
at 30 minutes. We have another meeting that let's say starts at 5 minutes and ends at 10 minutes. And we have another
40:19:27
meeting that let's say starts at 15 minutes and end at 20 minutes. So something like that. So essentially over
40:19:33
here we are having three different meetings. And now for these three meetings how many minimum number of
40:19:38
rooms we need to accommodate all the uh meetings. So clearly we can see that
40:19:46
essentially there exist an overlap between this this meeting and this meeting there also exist an overlap
40:19:52
between this meeting and this meeting. So because there exist an overlap that is causing us to create to have more
40:20:00
than one rooms because at any given moment two meetings cannot be two two
40:20:05
meetings are happening at the same time but they cannot be placed in one conference conference rooms. So now we
40:20:11
will have to determine that how many number of conference room we need. Well we will need in this case we will need two conference rooms. Why two conference
40:20:18
rooms? If we look at this start time and end time for all the meetings initially
40:20:24
let's say we have a conference room like this. So initially this first meeting takes place which starts at this 0
40:20:29
minute right. So let's say that okay this minute is this meeting is being taken place over here. Now when we reach
40:20:36
at this time number five we know that another meeting also needs to be started but this conference room is also already
40:20:42
occupied. So we cannot use this this conference room. So what we'll have to do is we'll have to use another conference room and uh let me draw it
40:20:50
over here. So we will have to use another conference room to accommodate
40:20:55
this meeting over here. Now at this five time number five we started the meeting.
40:21:02
But we notice that at time at value number 10 we also finished this meeting
40:21:07
which means that now all the folks that attended this meeting they are actually
40:21:12
coming out of the conference room and now this conference room is empty but this conference room is still occupied
40:21:18
with this original ongoing meeting. So that we will have to take care of. So at value number 10 we already emptied this
40:21:25
uh conference room but again we start seeing in this order. So we can find
40:21:31
that at time number 15 we still need one more conference room to attend the meeting. So we check okay this
40:21:37
conference room is already occupied. So we can't do anything. But this conference room is empty because this
40:21:43
meeting has already been completed which means we don't have to worry about it. So this meeting at that starts at time
40:21:49
number 15 needs to be placed on this second conference room again and then it
40:21:56
ends at minute number 20. So at 20 minutes all the PE folks they empty the
40:22:01
this conference room. So again this conference room is now empty. Now there is no one but this meeting is still
40:22:06
going on. And when the time clock hits 30 minutes, we can see that okay the now this particular conference room the
40:22:14
first conference room is also going to be empty and folks are going to leave it at time number 30. And this is basically
40:22:21
the approach. So at any given moment the maximum number of conference rooms we are using to accommodate all the
40:22:26
meetings were actually two. So in this case we will need to return two as our answer. The question comes that why we
40:22:34
were able to generate this two? Why not some other value? And how do we
40:22:39
programmatically solve this problem? Well, the approach is actually quite simple
40:22:46
that over here what we what we needed is only three only two things. Uh the first
40:22:53
thing we needed is that at any point what was the start point what is the end point and based on the start and end
40:23:00
points we can actually uh come up with some very interesting results. So if we
40:23:06
see over here in this example what we were doing is that at any given moment
40:23:11
we are iterating over this time sequence and based on the starting point of the
40:23:17
meeting and ending point of the meeting we are either occupying the room or we
40:23:22
are emptying the room and just by keeping track of those two activities we
40:23:27
can determine that what is the minimum number of rooms that we are that we need in order for us to accommodate all the
40:23:33
meetings. Let me show you how. So over here again keeping up with the same example. So let's say that in this
40:23:41
example we already have the start and end times of all of them. So what we can do is we can have two arrays.
40:23:49
So first array would be for starting values and second array would be for ending values and we are going to sort
40:23:57
both the arrays based on the timing. So over here the sorting values would be
40:24:02
that what are okay. So what are the starting points? Starting points we have over here is 0, 5 and 15. So we have
40:24:10
three starting points originally and over here you can see that they are in sorted order. But if you look at the
40:24:16
original input we can't see them in sorted order order like uh they can be jumbled up or the values can be given in
40:24:23
any order. Right? So first of all we will sort everything and then that sorting is going to take big of n login
40:24:30
time. So that is uh some activity that we will discuss when we come to the time and space complexity. So initially the
40:24:38
sorting position currently this value is 0 5 and 15. Okay. So let me get rid of
40:24:44
this extra space. Okay. Now for the ending values the
40:24:50
ending values are uh 10 20 and 30. So
40:24:56
again let's sort sort based on the ending values. So 10 uh 20 and 30. And
40:25:05
now what we are going to do is at any given moment we are going to check both of these uh arrays.
40:25:12
And in amongst these two arrays we are going to see that what is the minimum value amongst either starting value or
40:25:19
ending value. And we are going to keep a count or keep a variable called
40:25:24
meetings. And we are going to increase the value based on whatever the results
40:25:29
we find over here. So let's try to do that. So initially we are we start we
40:25:35
compare these two values. We see that okay zero is minimum amongst these two. So because we are starting a new meeting
40:25:42
which means we will have to occupy a room and because we have to occupy a room what we are going to do is we are
40:25:47
going to do meeting plus+. So essentially the the value of meeting was originally zero. So we are going to keep
40:25:53
the value as one. Now we are going to now we are keeping the value as one.
40:25:59
What we are going to do is we are going to iterate over. So this we are keeping
40:26:04
at this because this this has not been updated in the ending value. But in the starting value this zero has already
40:26:10
been taken care of. So we ignore this case. And now for the starting value we compare this uh value number five. So
40:26:16
again we compare this value number five with this value number 10. We see that okay the smaller value amongst these two
40:26:22
is still the starting point in the starting array and because we are starting a new meeting which means that
40:26:28
we haven't completed any meeting but we are starting a new meeting. So because we are starting a new meeting we'll
40:26:33
still have to add the value of meeting. So currently the number of conference rooms we will need we are going to
40:26:39
increase it to two. And by the way this you can call it consider as meeting rooms. I just named it meeting just for
40:26:46
simplicity. Okay. Now again we uh we are done with this five. So again for the
40:26:52
start value we increment and over here we are still at this position number 10.
40:26:57
Again we compare this 15 and 10. So over here we realize that this 10 is actually
40:27:02
smaller than 15 which means we are ending a meeting before. So now because we are ending the meeting so we we we
40:27:09
will jump on this ending array. Now we will come to this place and because we
40:27:15
ended a meeting which means we will have to subtract the value over here. So what
40:27:20
we are going to do is rather than having two we will reduce this value back to
40:27:25
one but and so now we are at this 15 and 20. So we compare both the values and we
40:27:32
realize that okay this 15 comes first. So we are starting a meeting now. So
40:27:37
because we are starting a meeting we will again do plus. So now this one becomes two and uh we compare this
40:27:45
meeting with this answer. So both are both values are two. So we don't need to update anything and uh that's why uh
40:27:52
over here we are done with this case. So now there is no more place to start the meetings. So actually we can end over
40:28:00
here. Why? Because over here the moment we are going to like reach this and this
40:28:06
value all we are going to do is we are simply going to reduce the the value of this meeting parameter back to one and
40:28:12
then again back to zero. So there is no point in us for doing all this work if the starting array has already been
40:28:19
dealt with and this would be our solution. Uh like this is a very simple solution to understand and easy to come
40:28:25
up with and this is also very optimal and it solves the problem efficiently. So let's see that what would be the time
40:28:32
and space complexity. The time complexity in this case is going to be bigo of n log n. So this is initially
40:28:40
for sorting as I mentioned earlier plus bigo of n. And this big of n is to iterate over the start and end array. So
40:28:48
uh in general we can write this as bigo of n log n only. And now we are done
40:28:53
with this one. uh in terms of space complexity for the space complexity it would be big of 2 n because we are
40:28:59
storing two arrays and in the both arrays we are storing some n values. So but in general we can write this as big
40:29:05
of n as well and uh this would be the optimal time and space complexity.
40:29:11
First of all we are going to check that if the given uh array of intervals is empty or not. If it is empty we are
40:29:17
going to return zero. That is not the case. We are going to create two integer arrays start and end.
40:29:24
And for both the arrays we are actually going to fill out all the values in the start where start array and end array.
40:29:33
Once that is done we are going to iterate over the given input and uh from the given intervals we are going to fill
40:29:40
out the start and end array. Once this is done we are going to sort
40:29:46
the given start and end array. And once sorting is done uh we are going
40:29:52
to initialize a couple of pointers. So we are going to name them as start pointer and an end pointer. And we are
40:30:01
going to initialize the values as zero. And these pointers are going to be used to iterate over this start and end
40:30:07
array. And once these two are done, we are also
40:30:12
going to have a variable called result uh to keep track of the number of
40:30:18
meeting rooms that are needed. And we are also going to initialize it to zero. And now uh we are going to run a loop.
40:30:26
But remember that we only need to run a loop until the start array has some values. So we are only going to iterate
40:30:34
over the start array because once start start array is done, the result value is
40:30:39
always going to go down. And at any point we are going to check
40:30:46
that whether the current start value is actually greater than or
40:30:51
equal to the end value or not. If that is the case, we will have to update the end array. And the reason we are doing
40:30:59
it is suppose we are given a couple of arrays like this that uh a meeting
40:31:05
starts at zero and ends at 10 minutes and there is another meeting that starts
40:31:10
at 10 and ends at 15. So in this case we can actually use just one uh room or one
40:31:17
conference room to iterate over. Why? Because first meeting has to end first before the second meeting starts. This
40:31:23
is a condition that is given and we are going to use that.
40:31:29
Hence, if this is the case, we are going to decrement the number of uh result that
40:31:37
is and we are going to increment the end pointer.
40:31:45
And if that is not the case, so which means that we essentially have a starting a meeting starting before the
40:31:53
previous meeting ending. And in that case, we will always have to increase the number of rooms needed. So we can
40:31:58
simply increase the result and we will also have to update the starting pointer.
40:32:07
And at the end uh once this loop is done, we can simply return whatever the
40:32:12
result we found. Let's try to run this code. Seems like
40:32:18
our solution is working. Let's try to submit this code. And we are actually solving this problem way faster than lot
40:32:25
of other Java solutions. And uh you can see it uh over here. So I will be posting this code in the solution uh in
40:32:31
the comments. You can check it out from there.
40:32:44
Hello friends, hope you're having a fantastic day today. So in this section we are going to do an entire course on
40:32:49
backtracking. It is a very popular data structure and algorithm technique that can be used in all sorts of practical
40:32:55
applications and tons of interview questions. In this section, we are going to learn that what is backtracking, when
40:33:01
to use it, how to use it, what is the typical time and space complexity, what are the benefits, pros and cons of using
40:33:07
and not using backtracking and also uh how to identify backtracking kind of
40:33:13
questions. My expectation is that by the end of this course, you should become a pro in all sorts of backtracking and
40:33:19
recursive kind of questions. So without any delay, let's get started. Now let's try to understand that what backtracking
40:33:26
is. This is not any particular data structure but rather this is a very important and very popular technique
40:33:33
that we can use in all sorts of different scenarios. Let's say that you are at a current scenario where you are
40:33:41
in a new city and in this new city you are currently located at your home and you are you don't have Google maps at
40:33:47
the moment but you do know that somewhere around your house or around the block there is an ice cream shop
40:33:54
that you are trying to find. So what you would do is you know that currently outside of your home there are two
40:34:00
different ways that go in each directions and amongst these two different ways there are also two
40:34:06
different possibilities that you can take in order to find the ice cream shop and ice cream shop let's say it lies
40:34:12
over here and where you can find the ice cream but you currently have four different options that you can choose
40:34:17
from where three does not lead to the ice cream so what would be the logical step you would take you would first of
40:34:23
all start your iteration from your home and You will take any pick any random guess. You know that at most you will
40:34:29
have to make four different check out four different shops on four different places. So let's say that you decide to
40:34:35
go down this path. Now once again at this path once again you encounter two different possibilities. So once again
40:34:41
let's say that you decide to go down this path. Now going down this path you realize that this is not an ice cream
40:34:47
shop. So if this is not the ice cream shop, what should be your most immediate measure? So logical step would be to
40:34:54
just do a backtrack operation back to the very previous point where you encountered the last possibility of
40:35:01
different items that you could have explored and once again explore those items as well. Once again after
40:35:06
exploring this you realize that this is also not an ice cream shop. So once again you will go back and after going
40:35:12
back you notice that at this juncture you explored all the possibilities. So now once again you will go back to a
40:35:19
point where you had some possibilities left. Now let's say that you come back to this moment and once again you go go
40:35:25
back over here once again you have two possibilities you coincidentally chooses this one and this one turns out to be
40:35:30
the ice cream shop and you just found your ice cream. So that is awesome. Now what we did in all of this the these
40:35:38
different jumps that we were taking on these were actually the backtracking operations that we were doing and what
40:35:44
was our logic it was quite straightforward that whenever we are heading out and whenever we have to make
40:35:50
any particular decision we would just mark that what decision we took and what
40:35:55
decision we are yet to take we will take one of the decisions once again if we encounter multiple decisions in such
40:36:01
manner we will pick any particular decision and Then let's say we did not find what we are looking for. We will go
40:36:08
back to the very previous place where we still had some unexplored items that we
40:36:13
did not take a look at. Try to explore those possibilities and then if we still don't find it once again go back and
40:36:19
repeat the same process. So you understood one thing very clearly that
40:36:24
we are actually repeating the same process we did at this point at this point and once again we would have
40:36:30
repeated the same process we did over here. what we did if we had some possibility like this on this place as
40:36:36
well. So logically we are just playing around with the same procedure with
40:36:42
different inputs and that is a very clear case of recursion and you understood very correctly that
40:36:48
backtracking and recursion go hand in hand. Many times when you are trying to realize that hey this is the problem
40:36:54
where I'm dealing with lot of different possibilities and I need to do some stuff differently. In that case you can
40:37:01
come up with a backtracking solution that explores all the possibilities and all the subsets all the permutations
40:37:06
combinations you name it whatever he wants to say all the different parts and in that case if you try to think of
40:37:13
using recursion to solve the or implement that method things would become much more sense and this is the
40:37:19
true power of backtracking where it lies because you can explore all sorts of different possibilities no matter how
40:37:26
many number of possibilities that you have to check and you can find the answer you are looking for and keep on
40:37:31
iterating with relatively slow amount or slow volume of code and all everything
40:37:36
can be done using recursion because you are just repeating the same process for different inputs. So this is the core
40:37:42
concept of backtracking. So this is all that is needed to be done. It is a very
40:37:48
simple uh and very popular type of uh practice that can be used with all sorts
40:37:54
of data structures. You can use it with arrays, you can use it with trees, you can use it with graphs, you can use it
40:38:01
with strings, you can use essentially use backtracking with all the different kinds of data structures that are
40:38:06
available and it would work just perfectly fine. Now let's try to understand that what are the different
40:38:12
benefits and what are the different cons of using or limitations of using backtracking. Number one benefit is that
40:38:19
whenever you have to explore all the possibilities or all the subsets all the permutations or everything every single
40:38:25
path that you have to take backtracking is a really good uh and very profound tool in order to do this one. Next thing
40:38:33
is it is simp relatively easy to understand and very simple to implement as well and next thing is that it leads
40:38:40
to solution no matter what. So you can you can guarantee to be finding the
40:38:45
solution because you are essentially leaving no stone unturned. So there are some good benefits of using
40:38:50
backtracking. The problem is with backtracking solution typically notice
40:38:56
that with at every single moment let's say that you have two choices to make and you keep on making those two cho
40:39:02
choices very soon the number of choices you have to make becomes exponentially higher because at every single location
40:39:08
you are updating or increasing in two to the power of n uh type of time complexity and this can be one of the
40:39:16
major drawback of using backtracking solution because many times you are working with factorial or 2 to the^ of n
40:39:23
or maybe like n cq n² sometimes of like these kinds of expensive uh time and
40:39:30
space complexities and that's why you need to be very sure that whenever you are using a backtracking solution that
40:39:36
that is like the only way that you are trying to use it. So if you are sure about it then it becomes a really good
40:39:42
or and powerful tool because many times uh if you try if the given problem is
40:39:48
structured in a different manner you can also try to think about some greedy approach or maybe some uh like shortcuts
40:39:55
or binary search approach in order to make your backtracking more efficient. So just try to understand this point
40:40:01
because this can come in handy in the future. And now I hope that my explanation made sense to you that what
40:40:08
backtracking is. I you also understood that why we need to use uh backtracking
40:40:13
with typically recursion. So the lead code problem we are going to do today is called subsets and we can
40:40:19
see that this one is a medium problem and also a very well-like problem on lead code. The statement is quite
40:40:24
straightforward that we are given an integer array called nums and we need to return all the possible subsets of this
40:40:30
given array. So possible subsets means every single possible values or combination of values you can make out
40:40:37
of the given array. Let's say that we are given an input element like this and we are trying to determine that what are
40:40:43
all the possible subsets that we are going to be able to make. So we know that for any given n value we can make 2
40:40:48
to the power n subsets. So in this case we should be able to make four different subsets. Let's understand that what
40:40:54
these subsets are going to be. So first subset is going to be quite obvious that is going to be an empty uh array.
40:41:00
Nothing more than that. And because that is a subset of this by default because
40:41:06
if we remove both of these values still we have an empty array which we are able to generate using this. Next way we can
40:41:13
also generate values just one. Same way we can also generate value just two and same way we can also generate value one
40:41:20
and two. So logically using this logic we should be able to try to understand
40:41:25
that what is the way we can approach this question and what I am suggesting
40:41:31
is that this is nothing more than a decision making algorithm where at every
40:41:37
given step you are making the decision on whether you are going to include that element in your answer or you are not
40:41:44
going to include that element in your answer and based on that you should be able to come up with these four answers.
40:41:50
So let's try to let me try to explain you my approach using this example and then we will try to understand this for
40:41:57
bunch of different other examples. Let's say that currently we are we are given these two these two elements as part of
40:42:03
the input. Now the in order to generate the very first subset we have two options and let's say that we are also
40:42:09
iterating over this given input array in this fashion. So the moment we iterate over this input array one the very first
40:42:17
option we have is that we should should we include this one in our answer or should we not include one in in our
40:42:24
answer. So let's generate those subsets. So if we don't include one we come up with an empty list. If we decide to
40:42:31
include one then also we are going to be able to generate uh subset like this
40:42:37
one. Same way uh next we have the option that after this one we now the next
40:42:43
element in the loop is two. So once again we have the same option that whether we should include this two in
40:42:49
the answer or we should not include this two in the answer. So let's say that if we decide to include this two in the
40:42:55
answer then we are going to be dealing with values 1 and two. Then once again we still have one more option that is
40:43:02
because remember we are trying to build the subsets. So with every single value we iterate to the next we are also going
40:43:09
to calculate the possibility by removing the previous value. So let's say that we decide to remove this one completely.
40:43:15
Then also we still have one more option that should we include this value number two inside the answer or not. So once
40:43:21
again we will have one more subset like this. And then we have reached to the end of our loop. So we don't have any
40:43:27
more options. So this logic gives us the correct answer of all the number of
40:43:32
subsets that we can make where what we did is at every given step we check that
40:43:37
whether including that value or not including that value would result in some sort of subset marking those subset
40:43:44
in our answer array list we are going to create and this answer array list is going to be list of list because it's
40:43:50
this array is also going to contain bunch of different array values and where we are storing the value of every
40:43:56
single result that we are calculating. So once again let me try to go and
40:44:01
explain this for a broader scenario the solution I'm proposing and then it should make you absolutely clear on what
40:44:08
is the approach we are suggesting. Basically at every single step we are going to make a decision to whether to
40:44:13
include that element or not and every single answer we generate it is a it is one of the subsets. So let's say at this
40:44:20
very first position we have two options whether to include one as the part of the answer or not to include one. So
40:44:26
let's see both possibilities. If we don't include one, we have an empty list. If we include one, we have one
40:44:32
value that is value number one. Let's say we decide to go down the path of including value one. Once again, we have
40:44:38
two possibilities. Whether to include value two or whether not to include value two. If we decide to include value
40:44:45
two, we are going to have one and two. If we don't include value two and go to the next element, we are going to have
40:44:50
value 1 and three. And that's it. Now these are all the elements we have. So we won't be able to go any further. But
40:44:56
we still have a decision to make which is over here that after this 1 2 do we need to include three or not include
40:45:02
three. So let's include three. So that is going to be this decision 1 2 3. If we don't include three then that then it
40:45:08
is just 1 and two. That's it. Now once again now we took care of all the possibilities with value number one. Now
40:45:15
let's try to work on value number two. So once again we have the possibility of including two or not including two. We
40:45:21
already calculated if we don't include two then it is going to be an empty list. So let's include two now. So by
40:45:27
doing that we are going to have one uh decision tree like two. Now at this two
40:45:33
once again we have two possibilities include three or not to include three. So let's decide to include three then we
40:45:39
are going to have value one uh two and three and that's it. Now if we don't include three, we already calculated
40:45:45
that possibility over here. And last one is value number three. So once again for this value number three we have two
40:45:51
possibilities whether to include this one one and two we already calculated
40:45:56
all of these by including one and including two. If we don't include one and two then we have we only have one
40:46:02
possibility that is to have value number three and that's it. So these are every
40:46:07
at every single decision that we are able to generate we are able to see that what are the values being generated by
40:46:15
those decisions and all of these are actually the answers or the subsets that
40:46:20
we need to record and that's it. This is the crux of the the entire problem uh
40:46:26
and the whole solution. So we can see that we are being able to generate in total these eight values and these eight
40:46:33
values are actually the answer we are looking for. Now let's try to think about that how did we generated this
40:46:39
answer. The logic is quite simple. We do this recursively and using backtracking.
40:46:46
And how do we do backtracking and recursively? Let's understand this with
40:46:51
first of all what is the recursive pattern. So we know for recursion we need we need two items. First one is a
40:46:57
base case and second one is a recursive function. So base case is quite obvious
40:47:03
that whether we have ex executed all the possibilities or we we completed every
40:47:09
single elements. So both of these base cases works perfectly fine because at
40:47:15
every step we would be able to record generate an answer. So this is our recursive function that whether we
40:47:21
exhausted all the possibilities or we we don't have any more elements that we need to traverse over. Now what is the
40:47:27
recursive function? It is also quite obvious that as long as any particular elements exist then once again record
40:47:36
both possibilities of including that value and not including that value as
40:47:41
part of the answer. After doing that once again do a recursive call back to
40:47:47
the same function in order to check that if you include that value then also what are the remaining values persisted call
40:47:54
back the recursive function with those values once again. If you don't include that value what are all the remaining
40:48:00
values persisted once again do a call back operation and if there are no other values left then basically just do a
40:48:06
return call. So this uh recursion would be able to generate the answer. Now why
40:48:12
do we need to do a backtracking and that is also quite obvious because what we are doing is that we are building a
40:48:18
decision tree. So let's say that we are given this values 1 2 and three. So once again for we first check all the
40:48:24
possibilities for this value number one. So we check their value number one. Then we check value for 1 2 and 1 3. And once
40:48:30
again we check for value 1 2 and three. And after at this moment we will once again have to go back and see that did
40:48:38
we miss out any particular element or any particular possibility that we did not check. So so far we did not we
40:48:44
checked all the possibility over here. We checked all the possibility over here. Once again we do a roll back. Once again we check did we check all the
40:48:51
possibilities? Yes we did. So once again we do a backtracking and go to the next element and once again repeat the same
40:48:56
operation. And that's why backtracking is the backbone of this problem that allows us to solve this problem
40:49:02
flawlessly and pretty smoothly. So this is how we are going to be able to use uh
40:49:07
solve this problem using backtracking and recursion. Uh and this is these two
40:49:12
typically go in hand in hand. Whenever you try to solve some problem using backtracking most likely doing it
40:49:18
recursively would make much more sense. We already know what is going to be the time complexity in this case. that is
40:49:24
going to be big of n multiplied by 2 ^ of n because that is all the possibilities we will have to check. Now
40:49:30
let's quickly see the coding solution. The coding solution is quite straightforward. Uh first of all we have
40:49:36
our subsets class where we are receiving an a nums as part of the input. Then we
40:49:42
are generating a list of array list to store our result. And then we are going to call our recursive method that we
40:49:49
have created that is called generate subsets. Now we are passing in the current index, the starting index. Then
40:49:55
we are passing in the nums array and we are also passing in a variable to store our result. Uh and also we are passing
40:50:02
in a new array list or the current array list that we are going to be creating that we would be adding at every single
40:50:08
subset iteration. Now let's see our helper method. So first of all the
40:50:14
moment we enter inside our sub uh subset we are first of all going to add whatever the current array list that we
40:50:21
have been able to generate it so far as part of our result as a new instance of the array list and then we are going to
40:50:28
have a for loop that is going to simply iterate over every single index position inside our nums array where we are going
40:50:36
to check for the following. First of all, we are going to add the current value as part of the current iteration
40:50:42
that we are building which would be added into the array list or in into the result in the next iteration of the uh
40:50:50
recursive call. Then once again after adding the current value we are once again going to call the current value as
40:50:57
part of the result um or sorry as part of the recursive call and this is our recursive function. And after that once
40:51:05
that is done we are going to be removing the current element in the next iteration. Why? Because let's say we are
40:51:12
dealing with five elements. Then at every given instance we need to remove
40:51:17
one elements after we have we are done iterating every single possibility at that value. So this is that step and
40:51:25
that's it. So by the end of this array, every single value should be populated inside our result uh array list that we
40:51:31
have been able to create it and uh at the end of this sub uh recursive call is
40:51:37
done. We are simply going to return that value. So let's try to run this code.
40:51:44
Seems like our solution is working as expected. Let's submit this code. And our code runs 100% faster than all
40:51:51
the other solutions. and also it is excellent in terms of uh memory utilization as well. So once again the
40:51:58
solution of this code is available on our GitHub repository. So you can go and check it out from there. Thank you.
40:52:14
Now we are going to be solving the problem subsets 2. Now this is very similar to our original subsets problem
40:52:21
but there is a slight difference. Now we can see that this one is a medium problem and also a very well-like
40:52:26
problem. The problem statement is that we are once again given an integer error nums that may contain duplicates. So we
40:52:33
need to return all the possible subsets plus we are told that the set must not
40:52:38
contain duplicate subsets. So there is only just one tiny bit of difference. Now let's first understand that what
40:52:45
does a different subset means. So let's say that we are given an input array like this. Then the number of subsets it
40:52:51
can contain is going to be 2 to the power of n. So where n is the given number of elements. So in this case we
40:52:57
have two elements. So we can expect that 2 to the power two which means four subsets we we should be able to create.
40:53:03
And these four subsets are going to be an empty list. A subset only containing value number one. A subset only
40:53:08
containing value number two. And a subset containing value number one and two. That's it. So this is the whole
40:53:16
solution. But the thing is I know we just solved this problem in like our subsets problem. So if you want you can
40:53:22
check it out from there. The thing is in this case the only difference is that let's say that we are given a value like
40:53:28
this where it the input may contain duplicates. Then this changes our
40:53:34
equation a bit because in this case we need to only return the unique subsets.
40:53:40
So in this case if we want to create the number of subsets definitely we can create 2 to the power of n subsets. The
40:53:46
issue is that we can create a subset we can create like an empty subset then we
40:53:51
can create a subset with just one. But once again if we try to create a subset with this two let's say then we can also
40:53:59
create a subset like this this two. And if we were to put both of these in the answer then there would be duplicated
40:54:06
entries. So we only need to just pick one. So that is number one thing. There can be one more duplicate in this case
40:54:12
and that duplicate could be that we can create a subset like this value one and two and we can also create a subset like
40:54:19
this where value is one and two. So if such kind of situation occurs then we
40:54:25
need to take care of that scenario. So basically making sure that whenever we have duplicated entries we just have to
40:54:33
keep keep them aside or not consider them for the current part of the subsets. Now we all know that what was
40:54:41
the strategy we used in order to calculate the subsets. Let's say that we only have just two values given and we
40:54:47
are trying to generate the subsets. Logic is quite straightforward. We are going to be using the backtracking on
40:54:53
top of it. We are going to be using recursion. Now let what is going to be logic for our backtracking that while
40:54:59
after calculating every single path for every possible subset then we are going
40:55:04
to be doing a backtracking and once again repeating the same operation. What do what do I mean by that? Let me just
40:55:11
explain. So first of all we are at the empty list position. Now over here we have the possibility to include this
40:55:17
value one or or not to include this value one. Same way we have the possibility to include this value two or
40:55:23
not to include this value two. Let's say that we decide that we are not going to include both of these one and two. So in
40:55:29
this case we can create a subset like this like an empty list and we will mark this as part of the answer. So let's say
40:55:35
that this blue line indicates that we already marked it as the answer. Now once again after marking this answer we
40:55:42
still somehow needs to go back and revert our operation. So in the previous
40:55:47
choice we decided that we are not going to select this value number one. But now let's say that we do decide to go ahead
40:55:53
to select this value number one. So once again we are we can create a subset where we are only selecting the value
40:55:59
number one. So once again this is also part of the answer. So I'm marking it with a blue line. But after doing this
40:56:05
once again we will have to do a backtrack and see all the possibility. So we already exhausted all the
40:56:11
possibility of selecting one and not selecting one. But thing is we haven't exhausted all the possibility of
40:56:16
selecting two and not selecting two along with this one. So let's say that along with this one we have the
40:56:22
possibility that whether we select two or not select two. So we not selecting two we already calculated but now we are
40:56:29
calculating one more possibility where we are selecting two. So we have values like one and two. Okay after doing this
40:56:35
we can do a backtrack. We did we check all the possibility at one. Once again we check everything so far but thing is
40:56:42
we haven't checked the possibility of only considering two. So once again we are simply going to be considering two.
40:56:47
And this is going to be our backtracking mechanism. On top of it, this is also
40:56:52
going to be our recursive function that I just explained where for the recursion we need we need two items. We need a
40:56:58
base case and we need a recursive function. So for the base case, it's quite straightforward that whenever we
40:57:04
create or we make any single decision, we simply add it to the answer. And this is our base case. After this for the
40:57:11
recursion, we go back to the next recursive call with that selected value
40:57:18
or not selected value and once again repeat the same process for the next upcoming remaining elements inside the
40:57:24
array. So this already makes sense. We already do this. But the only issue in
40:57:30
this case is that we simply don't want to consider let's say that we are given values 1 2 and two. So now in this case
40:57:37
once I'm making the decision let's say I put down the empty array then I put down a list with one right now at this one I
40:57:44
have two possibilities first possibility is that I'm going to be considering this two and second possibility is I'm not
40:57:49
going to be considering this two so let's say I decide to consider this two then I should be able to create an input
40:57:55
array like this or like a a new subset like this once again let's say that I go
40:58:01
to and let's for simplicity let's assume that this value is currently three Okay, not two. So if this value is three, then
40:58:08
I create one possibility where I'm considering two. I can also create one more possibility where I'm not
40:58:13
considering two or which means there can be a subset like this 1 three. But in this case rather than this value being
40:58:20
three, this value is also two. So it's the same value. So if I try to do this
40:58:26
possibility in this case then I'm just stuck. I'm left with only this value. So
40:58:31
what I can simply do is that I can take the given input. Let's say the given
40:58:38
input array is like this. But it it right now it is already sorted but it is
40:58:43
possible that this may not be sorted. We could have given values like this. So once again we if we want to do the
40:58:49
solution what I'm suggesting is that whatever values we are given we simply sort those values. So let's say we get a
40:58:56
nice looking values like this. After sorting all we simply do is we check
40:59:02
that at any given moment the whenever we calculated a possibility with this two
40:59:08
now we are trying to calculate another possibility we just check that the current element we are considering for
40:59:15
the possibility if that element is same as the previous element then we just
40:59:20
don't consider that possibility that's it this is the whole solution so now what would happen in this case we will
40:59:26
have an empty list we will have value with one. Now we will have one more subset with one two. Now after this one
40:59:32
two we still have two possibility whether to include this two or not to include two. So let's say that we do we
40:59:38
decide to include two. So then we still have one more subset like this. So we also consider that after this one we are
40:59:45
doing the doing our backtracking by removing the last element added. Uh we do the backtrack. We don't need to
40:59:51
calculate this one because we already know that it's the same element. We go back to one. We check all the possibilities with this one. So now we
40:59:58
are at this position number two. So we decide to include two only. This is a new subset. We add it to the answer. Now
41:00:04
after at this two we have the option that whether I'm going do we need to add
41:00:10
this value or not to add this value. So this value is quite straightforward. It's 22. It's a new subset. So we
41:00:15
haven't calculated that. So we can simply add this one. Now after calculating this once again we go we do
41:00:21
a backtrack. Now at this backtracking location now our time is to move to the
41:00:27
next element and not consider this one. But once again while making a decision for this one we check that whether it
41:00:34
matches the previous element. Yes, it matches the previous element. If it matches the previous element, what is the point of considering this for the
41:00:40
subset? So we are not going to do that. And that's it. This is the whole solution. And if you see the coded
41:00:46
approach, it would make much more sense. Plus you already know that how does the calculating subsets work because we
41:00:52
already saw that in the past that uh the whole explanation and the whole 9 yards. I just reexlained the whole thing and I
41:00:58
also explained that why we are adding this tiny logic to our already beautiful
41:01:04
solution. Now let's quickly see the coding approach. So very first thing we are doing is creating a new array list
41:01:10
where we are going to be storing the results. Then we are simply sorting the given input array. And then we are
41:01:16
calling our backtrack recursive helper method where we are passing in the new result where we are going to be storing
41:01:22
the array list of lists. And we are passing in the new instance of the array list to store the current list that we
41:01:28
are iterating over. Then we are going to be passing in the in given input nums. And we are also going to be passing in
41:01:34
the starting index where we are looking at. So initially we are starting from the index zero. So we are just going to
41:01:40
pass in zero. Now let's see our helper recursive method. First thing we are doing is whatever value we have in the
41:01:46
current list we are adding it into the answer. So during the very first call we are adding just an empty list into the
41:01:52
answer as well. Next we are iterating we are running a for loop from the start to the end of the given array. Plus we are
41:02:00
just checking for a very simple condition that if the given input I is
41:02:05
greater than start and the current element is equal to the previous
41:02:10
element. If this is the case we simply continue. If that this is not the case
41:02:16
then we simply add the value to the to our current array list. Then once again we call our recursive function. After
41:02:23
the call comes back from the recursive function. We remove the very last element added inside the current array
41:02:28
list. And then we repeat the same process until we are done with the entire for loop. And this should
41:02:34
populate our results completely. So now let's try to run this code.
41:02:40
Seems like our solution is working as expected. Let's submit this code.
41:02:46
And our code runs beautifully faster than all the other solutions and also
41:02:51
best in terms of space complexity. So once again the solution is present at our GitHub repository. So feel free to
41:02:58
go ahead and check it out. Uh till then thank you.
41:03:14
Now the lead code problem we are going to solve is called permutations. And we can see that this one is a medium problem and also an extremely well-like
41:03:21
problem. The statement is quite straightforward that we are given an integer array called nums of distinct
41:03:26
integers and we need to return all the possible permutations that we can make and good thing for us is that we can
41:03:33
return answer in any order. So first let's try to understand this with few example. Let's say that in the input we
41:03:40
are only given one element then we can only generate just one permutation. So this is what we need to return. But if
41:03:47
we are given more than one element, let's say 1 and two, then we can actually generate two permutations in
41:03:52
this case. First permutation is going to be the same value as it is. In the second permutation, we are going to have
41:03:58
the values being flipped around between 2 and 1. So these two are the permutations that we need to return.
41:04:04
Let's take one more example. Suppose in the input we are given the values 1 2 and three. Then we can basically
41:04:10
calculate that we should be able to make six permutations in this case. Why? Because for any particular given numbers
41:04:17
you can make n factorial permutation. So in this case we are given three elements. So three elements is going to
41:04:23
be 1 multiplied by 2 * 3 as in 3 factorial. So in this case the answer is
41:04:29
going to be six. Now let's see that what are all these six elements are going to be. Well so these are all the six
41:04:35
permutations we can make. Now logically this is nothing more than a decision making element or decision-m algorithm
41:04:43
because over here we can see that if we have to make permutation of this element let's say that I have three blocks where
41:04:51
I can fill in values. Now let's say for some reason I decide to put three in the first block then I know that I still
41:04:57
have two values where I need to fill out something. But thing is I can only fill out between this value one and two not
41:05:04
this value three. So once again I can repeat the same process and let's say randomly I decide to pick value number
41:05:10
one. So now for this last element I only have just one possibility and that is to
41:05:16
fill in this value number two and this the moment it reaches to the length of this previous one we can determine that
41:05:21
this is one of the permutation that we can store as part of the answer. Now after storing this we need to check that
41:05:28
whether keeping this three over here at the beginning are we leaving out or done
41:05:34
being done with all the permutations. No there are still possibility of permutations left. Let's say that we
41:05:40
decide to elimate eliminate this value number two over here and this value number one over here. Now once again
41:05:45
keeping this three on this place once again we have the option that instead of selecting one we can actually select two
41:05:52
over here. then we will have one over here and this would be a new permutation. So visually this is very
41:05:58
simple to understand that how does this function but thing is implementing this is slightly tricky. So what I'm
41:06:05
suggesting is that we actually use the same algorithm that we just saw but we
41:06:11
apply it using the logic and possibility and concept of backtracking. Plus on top
41:06:18
of it after using the backtracking I also suggest that we use a recursive approach to recursively recall the same
41:06:26
function with different inputs. And why am I suggesting this is because number one we already know that we are
41:06:33
repeating the same process. All we are doing it is that the input we are given we are picking one value in we are
41:06:40
marking that particular value with one of the values and for that let's say that over here we have one. So once
41:06:45
again now we have two possibilities. First possibility is that on this place for the second place we can fill in the
41:06:52
value two or we can fill in the value three. Once again let's say if we decide to fill in value number two then we are
41:06:58
only left with just one possibility for this last element that is this value number three and the this whole path
41:07:05
defines one of the permutations. So this we will be able to mark as the answer and then if we go decide to go down this
41:07:12
path once again the values are going to 1 3 and two. So this is going to be our second permutations and once again we
41:07:18
can mark this answer as well. So now let's say that what are the things we
41:07:24
need to solve this problem and how we are actually going to be doing that. I just explained that we are going to be
41:07:29
using backtracking plus recursion. So let's say that what do we need for our backtracking function. The idea is quite
41:07:36
straightforward that we will keep on going in one direction until we reach to
41:07:42
the length of the given input. Once we reach to the length of the given input, we will mark that uh entire path and as
41:07:50
part of the one of the answers and we would put it into our list of list that we have created to store our answers or
41:07:57
results. Once doing that the idea is to once again do a backtrack and after
41:08:03
doing the backtrack once again see that what is the potentially different path that we could have taken and once again
41:08:09
once we reach to the answer we basically store that answer. Now there are two critical parts in this case that we will
41:08:16
have to consider. Number one thing is that we will need to know at some point that what are the values we have already
41:08:23
calculated and what are the values we have not calculated so far. So what I'm suggesting is that let's say you decide
41:08:29
to put one over here then I would need some sort of way for my computer to tell me that this one is already part of the
41:08:36
function. So for that I'm suggesting to use a used array or like array named use
41:08:43
and the moment we add any particular value inside the current consideration
41:08:49
for our recursive function we are going to mark this used function as true or false. So this is this would be my used
41:08:55
array of boolean values and currently I would mark that this is true which means I'm currently considering one. Then once
41:09:03
again let's say that now I have I know that through my used array I only have two more possibilities left because this
41:09:09
one has already been filled. So for the next element I'm going to consider this value number two and once again I'm
41:09:15
going to mark this value two as being used as one of the decisions. After doing that once again I'm going to mark
41:09:21
this value three and then we I'm going to mark this three as being used. But the thing is because I reached to the
41:09:27
end of the list. So the moment I reach to the end of the list, I can mark this answer 1 2 and 3. And after marking this
41:09:34
answer, I can actually go back and I can go back in time with my recursive function and say that over here instead
41:09:41
of using two now I have decided to take another path where I'm going to be considering three as part of the input.
41:09:48
And in order to do this one I will need to constantly update this used array. That is number one thing. Second thing
41:09:54
is in order to calculate this path I will also need to have an a current array or array list to store this path
41:10:01
as well that these are the values we are currently iterating and the moment we identify that we have reached a new
41:10:07
answer then for the next iteration of the recursive call I simply need to regenerate the entirely new array. So I
41:10:14
know my solution might confuse you a bit but let me just give you this uh with
41:10:20
like using two examples. So let's first quickly take the example of simple one and two values. Okay, the logic is that
41:10:26
we are going to have a recursive function that is going to store um so for the recursive function I did not
41:10:32
explain but basically for the recursive function we need two items. So we need a base case and we need that what is going
41:10:37
to be our recursive call. base case is quite straightforward that the moment we identify that our given current n or the
41:10:44
current length of the given input is equal to the original n of nums then we
41:10:51
we have ident we have found the correct path in this case we would mark the current path inside the answer and after
41:10:58
marking that we would we would basically return so this is going to be our base case now for our recursive function the
41:11:06
idea is quite straightforward that we are going to pick one element right now and through that one element we are
41:11:12
going to be marking the used array for that particular element to be true and then we are going to call the recursive
41:11:19
function once again with the remaining portion because we still haven't identified all the values. Once we
41:11:25
identify all the possibilities uh and we receive an answer back then we are going to eliminate the last element we had
41:11:31
inside our recursive function to be turned out to be false and keep on repeating that in order to calculate
41:11:37
other possibilities. So let's first see for this example the idea is that first of all over here I have two possibility
41:11:44
let's say I mark number one element as being used and I have a current list where I'm going to store that what is
41:11:50
the current path I'm taking. Okay, I took one. Now I'm once again going to call for the next element. So now I call
41:11:58
for the next element that is obvious choice two. So I mark two and now I know that my length of this current has
41:12:04
reached to the uh n. So I'm going to mark this as part of the answer 1 and two. After doing this once again I'm
41:12:11
going to do a backtrack call. During the backtrack call I'm going to mark this one as not being used and two as not
41:12:18
being used. And then I'm going to be iterating over this given input in this fashion. So I already took care of this
41:12:24
element and now I'm going to start taking care of this element. So now I have my two as being used. Now I have my
41:12:30
current new current instance being created where I'm starting the path from two. And I'm going to go down to the
41:12:36
next path. So I only have one possibility that is to add value number one. So I'm going to add value number one over here. Mark one as being used.
41:12:43
And because this n is correct. So once again mark the another answer as 21 and
41:12:49
now I have my answer that I was looking for. So after this I realize that in my
41:12:54
existing loop I already enu be done through all the elements inside the given input. So which means now whatever
41:13:01
I have in the answer I can simply return that. So now if you want you can directly go to the coding approach if
41:13:07
you already understood what I meant. If you didn't understood then let me also do the same iteration for this path as
41:13:14
well. And once again repeat the same procedure. So logic is we are going to be iterating over every single element
41:13:20
one by one. That is number one thing. Next thing is the that we are going to
41:13:26
have our current uh list or the current values we are iterating over and we are going to have a used array where we are
41:13:32
going to be storing that which are the elements we have already used so far in the current iteration and we are going
41:13:38
to be updating the values one by one. So let's say that in the current path I add value number one. So I'm starting the
41:13:43
path from value number one. After one I decide to add uh value number two as an
41:13:48
input. So once again I do that and after this two I add value number three. So the moment I add value number three my
41:13:55
length is equivalent to so I'm going to store the answer 1 2 3. After storing this now once again I I do a recursive
41:14:04
call. So I basically break out. So which means I will have to remove the last element I added. still keeping one I
41:14:10
still have one more possibility that I haven't tested. So once again I'm going to mark three as being visited. So now
41:14:15
I'm going to take one more path. And by the way this is going to be a new instance where currently the nodes I have visited are 1 and three. And next
41:14:22
time I'm going to be visiting the value two because that that element is left over here. So once again I'm going to be
41:14:28
marking two and I'm going to have one more uh possibility 1 3 and two. Once
41:14:33
again uh now I do a backtrack. So backtracking would make sure that I took
41:14:40
care of three over here. I took care of two over here and all of these things are done. So now my used array need is
41:14:47
being backtracked to all the way to the beginning. So now once again I'm going to repeating the same process but now
41:14:54
this time with value number two and keep on doing this recursively until we reach to this very last element three where we
41:15:01
have all of the six possibilities calculated and this is the whole solution. So now let's quickly see the
41:15:06
coding solution and that would make much more sense. Now first thing we are going to do is that we are going to create a
41:15:13
new array list which is going to store our results. So now you can see that this one is an array list that stores
41:15:19
different array list inside. Then we are going to initialize our used boolean array uh in order to keep track of that
41:15:26
what are the current elements we have already used. And then we are going to have a helper method called backtrack
41:15:31
where as an input we are providing our result that we have calculated so far. Then we are going to have a new array
41:15:39
new instance of an array list where we are going to be storing the current elements we are iterating over. Next we
41:15:45
are going to be passing in the given input nums. And lastly we are going to be passing in the new array used array
41:15:51
that we have created. Now first we are going to be checking for the base case that if the current size is equal to the
41:15:57
length of the original given array then we are going to add the results of the current array list inside the new
41:16:04
instance of a new array list and we are going to be doing a simple return. If that is not the case then we have our
41:16:11
for loop that we need to iterate over. So very first thing we are doing is that we are starting for from the zero and
41:16:17
iterating I until we reach to the end of the array. then we are first of all checking that if the given I value is
41:16:24
not used then we are going to be adding that value inside the current uh path
41:16:30
that we are iterating over. So we added that then we are going to be marking that particular element as true inside
41:16:37
our used array and after that we are going to be calling our backtrack for
41:16:43
method recursively where once again we are simply providing the results that we have calculated so far the current path
41:16:49
which now contains a newly added element and the nums input and the used array
41:16:55
that now contains that the current element is being used and that's it. Basically this should ensure that all
41:17:02
the work gets through and the moment the list size is correct then we would start adding those values inside the result.
41:17:08
But the thing is after the backtrack call we will also have to remove the lastly used elements. So we are going to
41:17:16
be doing that and we are also going to be removing that value the very last value that that we had in our current
41:17:22
list. So we are always updating that in order to calculate new possibilities and
41:17:28
this is the whole solution. Now I know it's hard to visualize but coding is very small and also you can understand
41:17:34
that how to generate it on a pen and paper. So you can just work around with different examples and it would make
41:17:40
sense to you. Now let me quickly run this code. Okay, seems like our solution is working
41:17:45
as expected. Let's submit this code and our code runs super fast compared to
41:17:53
all the other solutions which means this is an excellent approach. Now I know using an extra used array might hamper
41:17:59
with our space complexity but this is still a much faster result. So now I
41:18:05
will be posting the solution in our GitHub repository so you can check it out from there. Thank you.
41:18:19
Hello friends. Hope you are having a fantastic day today. So in this video we are going to do a very popular lead code
41:18:24
problem that is going to be pretty nostalgic for a lot of people. So without any delay let's get started. The
41:18:30
title of this problem is called letter combination of a phone number and now many of the iPhone users won't know it.
41:18:37
But in the past phone actually did used to look like this where if you have to type any messages you will need to do it
41:18:43
according to the keys that are present over here with the corresponding numbers and people were so good that they were
41:18:49
able to do it without even looking at it. But anyways now coming back to the question. This is a lead code medium
41:18:55
problem and also an extremely well-liked problem on lead code also has been asked
41:19:00
at tons of popular companies. So let's see that what does the problem statement ask us to do. Uh basically we are given
41:19:06
a string containing digits from 2 to 9 because notice that in this problem we
41:19:12
are only given the characters from A to Z present between the letters 2 to 9.
41:19:18
Now inclusive now we need to return all the possible character combinations
41:19:23
based on the given digit numbers and that that it can be represented. Uh for
41:19:29
our convenience we can return them in any order. So let's try to understand this with couple of examples. Suppose we
41:19:34
are given as an input just character number four. So how many characters does this character number four can
41:19:40
represent? Well only three characters. Uh so if we have to return this the answer is going to be G, H and I as the
41:19:47
answer that we need to return. But let's assume that instead of that we are given the input as like four and six. Then
41:19:54
what should be the answer? So we know that four can represent G, H and I and
41:20:00
six can represent M, N and O. So the answer is going to be the combination of
41:20:06
both of this GHI and Mno. So the answer would look something like
41:20:13
where you can see that currently we have nine entries and they are combination of all the characters from these two
41:20:20
entities and that's what we need to return. So this is the whole problem statement. So let's try to see that what
41:20:26
is the approach we can take to solve this problem. Now number one thing is that currently we are only given that we
41:20:34
are only given characters between 2 to 9 as an input and nothing else. So first
41:20:40
thing we need to do is that we will have to create a mapping so that based on any given input location we can actually
41:20:47
identify that if the character two is given we know that it can only have the possibility of storing ABC. Same way if
41:20:53
character number nine is given then it only has the possibility to store four characters wx Y and Z and same way we
41:21:01
can store this in any such fashion so that this lookup needs to happen in big
41:21:07
of one time. So we actually have two options to do that. Number one option is that we can actually create a hashmap
41:21:13
and inside the hashmap we can store all the entities and based on the key we can mark as the digits and their subsequent
41:21:21
values we can we can mark all of the entries. So that is option number one. This will yield in big of one time
41:21:26
complexity whenever we have to do the lookup. Second option is since we know for sure that we are only dealing with
41:21:33
characters between 2 to 9 nothing more we can also create an array and inside
41:21:38
the array based on the index positions we can store the values. So let's assume that because in the array we have values
41:21:45
like 0 1 and then two and all or so on and so forth. So for zero and one we can store as an empty strings because
41:21:51
anyways they are not going to be part of our inputs and starting from position number two we can start storing values
41:21:57
as a b c and stuff like that. Now this is only for our convenience purposes so that we can quickly look up what element
41:22:04
we are trying to find. Now this is the pre-work that needs to be done in the solution so that we can do it in the
41:22:11
efficient manner. Now let's see that what is going to be the optimal approach to solve this problem. Suppose as an
41:22:16
input we are given the characters 2 and three that we need to return. Now we know that two is represented by a bc and
41:22:22
three has been represented by d e f that we actually take this given input 2 and
41:22:29
three. Then we break this input based on all the digits it it currently has. So
41:22:35
first we get the digit two. For digit two whatever the characters that it can
41:22:40
represent we create three decision trees based on that. So currently it can represent A, B and C. So we create three
41:22:48
separate decision tree. And now since this is not the answer because we need to return the combination or the
41:22:54
potential combinations that can be there. So this is just a part of the answer that we have created so far. But
41:23:01
now we will have to complete the comp combination portion. So in order to do that the number one thing we will need
41:23:08
to do is to keep track that how many number of characters are currently present or how many number of digits are
41:23:14
present and how many are pending. So now three is pending. So we will append
41:23:19
three with each of these decision trees and we know that three is currently represented by these three values. So
41:23:26
once again for each one of them we are going to have three separate decisions
41:23:31
tree being made. Notice that currently at this very first location two, we only
41:23:37
had one entry per character inside uh our representation. But the thing is in
41:23:43
the input we were given 2 three 23 which means we were dealing with two character
41:23:49
letter but in the uh in the problem we are so far we are only at half of the
41:23:54
step where we only have just two which means after creating this possibility we
41:24:00
still have to wait to add the values to the answer until we find this path where
41:24:05
now the index position matches the total number of inputs that we are given. The moment this condition matches, we will
41:24:12
need to add it to our answer list. So because over here we only had one characters but now we had two characters
41:24:19
and even in the input we were dealing with two characters. We are going to add d a or a d in the answer. Same way ae is
41:24:27
going to be part of the answer. Same way a f is going to be part of the answer. And the good thing about this is because
41:24:34
this is same operation being done multiple times. So we can actually keep
41:24:40
on doing this. The moment we find out that this is one of the potential pair that we have already added to our
41:24:45
answer, we can actually backtrack to see if a still has any more values that it needs to add to the answer. And yes, AE
41:24:53
still needs to be added. So we will add a E. Once again, we will backtrack to A. And once again, this AF needs to be
41:24:59
added. So we will do that. Once again, we would backtrack to two. Now we have completed all the path with A. So we
41:25:04
will repeat the same process with B. And this is the whole answer we need to return. Now I know what I just explained
41:25:11
might have confused you a bit. So that's why uh when we do go into the coding
41:25:16
section I will explain the whole thing in much more clarity. But this is the whole approach. Basically we are simply
41:25:22
using recursion and backtracking to solve this problem because repeatedly we are doing the same operation and we know
41:25:29
that for uh this we need to have an terminating case. So terminating case would be that the moment we identify
41:25:36
that one path or one combination contains the same number of characters as the number of input that is given or
41:25:42
the index values then we need to add it to the answer and once again do the backtrack keep on repeating the same
41:25:48
process until we have exhausted all the possibility and uh whatever the answer we found we need to return that. Okay.
41:25:54
Now what would what is going to be the time and space complexity in this case? The time complexity is only going to be
41:25:59
the number of potential combinations that can be made which means the number of uh characters that are given. So
41:26:06
let's assume that this currently has 3 * 3 six characters. So whatever the value
41:26:12
is. So we need to do square of the number of given input for every single digit. So in total it is going to be the
41:26:19
number of combinations that are currently present. That is going to be the time complexity for the space complexity because we will have to
41:26:25
create an another array uh that contains all the mapping from the characters 2 to
41:26:31
9. We will have to store that but that is going to be limited in scope. So instead of calling this as big of n we
41:26:38
can actually treat it as big of one because the space is space complexity is not going to change. So now let's see
41:26:43
the coding solution. Okay. Okay. So first of all we are going to initialize our string array where we are going to
41:26:49
mark first couple of entries as blank and then we are going to mark all the values. So this is going to allow us to
41:26:55
iterate over all the digits to the letters and then let's start our code actually for the problem statement for
41:27:02
this method letter combination where we need to return a list of strings as the answer. So first we are going to
41:27:08
initialize a combination string that we are going to return as the answer and this is going to be the blank array list
41:27:14
so far. Now first we are going to check for an edge case that if the given number of digits is equal to null or
41:27:19
digit.length is equal to zero then we need simply need to return combinations. If that is not the case we are going to
41:27:25
call our backtrack method and we are number one thing we are passing this uh list that we have created. We are also
41:27:32
passing the input digits that we have received. We are passing an empty string that is going to be considered as the
41:27:39
current combination that we have so far and we are passing in zero as the current index values that we have
41:27:45
processed so far. Okay. Now let's see this backtrack method how does it work. So number one thing we are checking is
41:27:51
that if this given current index location if that is equal to the digit length which means we have an answer
41:27:59
that we need to add to our current combination. So we are going to add all the answer that we have found in the
41:28:06
current combination to our combinations uh array list that we have created. If that is not the case, we are first of
41:28:13
all going to differentiate the letters for every single index position. So
41:28:18
let's say in the input we are given value number two. Then we would have ABC as the uh letters passed on and then we
41:28:25
are going to run a for loop across every single letter. But now this time we are
41:28:30
recursively going to call back the method backtrack. We are passing in the same combination same digits but for the
41:28:37
current combination we have added the current combination plus the current letter we are working on. On top of it
41:28:44
we have also updated the number of increased value uh index value. So if in the previous iteration if we would have
41:28:50
passed in value number two in the next iteration we would have passed in value number three. And that's how we will be
41:28:56
able to start storing all the combinations in the current combination uh array uh uh string that we have
41:29:02
created. And this is it. So let's try to run this code.
41:29:10
Okay, seems like our solution is working as expected. Let's submit this code.
41:29:15
And our code runs pretty efficiently compared to lot of other solutions which is awesome. By by the way, you can
41:29:21
always find this coding solution in the GitHub repository we have. and the link is in the description so you can check
41:29:26
it out from there. Thank you.
41:29:38
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do a very important lead
41:29:45
code problem and uh I have provided the introduction of what are the things to expect from this video. We are going to
41:29:50
solve the combination sum problem and uh first of all I'll be showing that what are the top companies that have recently
41:29:56
asked this question from lead code premium. Uh we'll understand the problem statement. We'll also find the optimal
41:30:03
solution and we will also determine that what would be the intuition behind it. Uh we will create an example and we'll
41:30:09
walk through it and uh at the end I I'm going to write a Java code. I'm going to explain it thoroughly that uh how we
41:30:15
come up to it and uh also we will be explaining the time and space complexity. So first of all uh these are
41:30:22
the top companies this that have asked this this problem recently and uh if we
41:30:27
see from past 6 months to a year u it's eBay Google Goldman Sachs and these companies and in re pretty recently
41:30:34
Amazon has asked this question 20 times in its interviews Facebook has asked this question 18 times in its interviews
41:30:41
so I highly highly suggest you to take a look at this problem understand it uh
41:30:47
completely and uh then uh practice it as
41:30:52
much as you can. This is a medium problem and we are
41:30:58
given uh distinct integer called candidates and we are also given a
41:31:04
target integer and we need to return all the unique combinations of candidates where we can reach up to the target
41:31:10
value. Now this is a little bit tricky part to to find all the unique combinations for this target candidate
41:31:18
because uh let's try to understand this with an example. So over here we are
41:31:23
given the candidates as uh 2 3 6 and 7 and we need to reach the value number
41:31:29
seven. So we can clearly see that seven is already present over here. So we can return this one. The thing is we need to
41:31:35
return all the unique combinations. So one unique combination is seven. uh second unique combination and also we
41:31:42
also one more thing we can use the same number from the c candidate unlimited times. So if we apply this theory then
41:31:50
we can find another value that can reach to the sum of seven and that would be 2
41:31:56
+ 2 + 3. If we do that this also sums up to 7. So we need to return uh a list
41:32:02
where the two values are 2 and 3 and the second uh element is just seven. And
41:32:08
this would be our solution for this given problem.
41:32:15
Okay, let's try to understand this problem with a custom example. And it is really important to create your own custom examples because it shows that
41:32:22
you have the ability to think out of outside of the box and you can create test cases on your own. It it is a
41:32:27
really important skill to have for any engineer and especially fang engineers. So we are given three candidates 2, five
41:32:33
and six and we need to see that what are all the combinations we can get out of these combin uh candidates to achieve
41:32:39
the target value 8. Now just by looking at it we know that the two combinations we can create is uh 2 2 this is one
41:32:47
combination and the second combination we can create is 2 six uh and this would
41:32:52
be our answer. The thing is let's see that what would be the most in most basic solution we can come up with and
41:32:58
what would be the intuition behind it and based on that we would be able to create an algorithm uh that would solve
41:33:04
this problem. So initially we are at this position zero. Now at this position
41:33:10
zero we have three possibilities from which we which direction we can go. Uh
41:33:15
we can either go to this value number two we can go to the value number five or we can go to the value number six.
41:33:21
the because these are the three candidates that we are given and also we should not forget that the target value
41:33:26
we want to achieve is eight. Okay. So keeping this in mind we need to go and
41:33:31
pick a side where we need to go further and uh keep going. So again let's just
41:33:38
go on one direction for all the cases we can. So over here we are at two. Now
41:33:44
remember that we can use same element infinite times which means that there can be one possibility as 22 two of
41:33:51
course there can also be one possibility as 2 two two of course the thing is uh
41:33:59
notice that we need to put a constraint for the number of decisions we are making and the constraints is that if at
41:34:06
any point the the direction that where we are fetching all the candidates if
41:34:12
the sum of those can they can either be less than uh target they can either be
41:34:18
equal to target or they can be greater than target. These are the three possibilities we can have. If it is less
41:34:23
than target which means that there is still room for us to find the potential combination which means we can keep
41:34:30
further going on that direction. If we are already at value number eight or value whatever target we are we can
41:34:37
directly put this value in the result. But if we and which means that we have
41:34:42
found the combination. So there is no point in going further after we have already found the combination because
41:34:49
all the elements they are only going to add up to whatever combination we have
41:34:54
which means that we won't be able to find another sol condition uh combination with the same numbers that
41:35:01
were used to achieve this equal to. And the third option is that the value could be greater than 8. If it is greater than
41:35:08
8, why are we keep on going or to do more iterations and uh putting more more
41:35:14
strain in our computer? There is no point in doing it because we could have infinite options and if we do it this
41:35:22
would be like the most wor this would be like the best way to deplete the
41:35:28
resources of our company. So we don't want to do that. So now since we have
41:35:34
kept these things in our mind now let's see that what how can we use them over
41:35:39
here. So so far the sum we have found up until this point is only two but the thing is over here we have two candidates and the sum we have found so
41:35:46
far is four which is still less than 8. Uh this is six again still less than 8.
41:35:52
Now over here we can have one more possibility as uh 2 two 2 and two. And
41:36:01
if we do the sum of this, this is eight. Which means that this is actually equal to whatever the target value we had. So
41:36:07
we can add this to our result combination. We would have that we have
41:36:12
already find one value in our result and we will just add it as uh 2 2. This is
41:36:20
one combination that we have found so far. The thing is we are not done yet because we still have other candidates that we need to look at and uh we need
41:36:27
to check the possibilities. The thing is we have concluded at least one thing so far and that thing is we can't go
41:36:34
further down on this path because all the values would be greater than 8 and which is not what we want. So the only
41:36:41
way we can go is actually we can go back and see that have we missed out on any combination. So over here the next
41:36:49
possibility we can get is we have already used two as our candidate for
41:36:55
this value 2 two. So the next possibility we can over can have over here is uh it could be two 2 and five or
41:37:06
it can be 2 2 and six. So let's do sum of all the combinations. So some of
41:37:12
these combinations would be u 11 and some of these combinations would be 12.
41:37:19
Notice that both are actually greater than the value of our target which means
41:37:24
that we can't go further down at any of these position and we have exhausted all
41:37:30
the possibilities up until this point. So since we have already exhausted the possibilities up until this point the
41:37:35
only way we can go is we can go back at this position two we have exhausted all
41:37:42
the possibilities there can have one we found the answer and the other two we found that it cannot be part of the
41:37:48
combination which means that we have already exhausted all the possibilities for this value 2 to2 as well which means
41:37:54
that we can't go down but we can go up. So over here have we exhausted all the
41:38:00
possibilities so far? No, there are still room. There are still other possibilities that we can check. So,
41:38:06
let's do that. So, one possibility we can have over here is uh 222 which we already checked.
41:38:13
The next possibility could be 22 2 and the next possibility would be 2 2 6. So,
41:38:21
some of these values is actually 9 and some of these values is actually 10.
41:38:28
Again both are greater than whatever the target value we had which means that it we cannot go for down.
41:38:36
So we will go back. We went back over here. We check that we we went through
41:38:42
all the possibilities which means that we are done over here but so we can't go down any further on this path but we can
41:38:49
go up. So if we go up
41:38:54
we ask ourself a question that have we ex explored all the possibilities this at this position? No. The possibilities
41:39:02
we could have is 25 26.
41:39:08
So let's take this value first. So at 25 the current sum we have is 7. 7 is less
41:39:14
than whatever value we have as our target. Which means that we still have possibilities. The possibilities we can
41:39:20
have is uh 2 5 or 2 5 6.
41:39:30
Notice that over here we only had two possibilities where we can calculate it from. We did not had the possibility of
41:39:38
2 to 5. Why? Because we already
41:39:43
calculated it for this portion over here. Remember in the previous iteration we already calculated for this scenario
41:39:50
which also shows one very important property and that property is that out of our
41:39:56
candidates uh whatever the candidates we are given if we are at any particular position or any combination of positions
41:40:05
uh so whatever value we have as last we can only use that multiple times or we
41:40:11
can use the values that come after it. We cannot go backwards because we have
41:40:16
already exhausted those possibilities in an iteration before this. As I showed
41:40:22
you earlier that this we have already explored over here and this 2 to the five uh 25 we are exploring at this
41:40:30
position two which means that the only combinations we can make up after this point is either 2 5
41:40:38
something blah blah blah or 2 5 6 6 something something like this. But we
41:40:43
can't make like 22 225 because we already checked that over here. So, and
41:40:49
this is a very important property that we are going to use.
41:40:55
Okay. At this point, the sum we can have is 12, which is greater than 8. So, we
41:41:01
can terminate over here. We can't go down any further. And over here, the sum would be 13. Again, we can terminate
41:41:07
over here. We can't go down, which means we have to go back. So we come back at
41:41:12
25. We say that okay we have explored all the possibilities over here. We go to go back to value number two. Now the
41:41:19
thing is at value number two have we explored all the possibilities? No. There is still one possibility pending
41:41:24
which is 2 six. So at 26 uh this value and the sum would be 8.
41:41:32
Again this is really critical because we have found a pair that equals to
41:41:37
whatever target value we had which means that we will add this combination to our result list. So over here we will add
41:41:44
another entry 2 six.
41:41:49
And after adding this we have explored all the possibilities after this point
41:41:54
which means that we would go back. Now at this position two we have explored all the possibilities it could have and
41:42:01
because we have explored it we will again go back to our zerooth position. The thing is we are still at zeroth
41:42:07
position. So can we stop now? No, we can't stop because we still have a whole lot of possibilities that we haven't
41:42:15
touched so far because remember over here we still have this five and six pending. So let's see
41:42:23
that what could be the possibilities over here. Now at five again we can only
41:42:28
have two possibilities as explained earlier. We could have either 55 or we
41:42:33
could have 56. So let's do the sum of these values. So 55 the sum is actually 10 and 5 6 the
41:42:42
sum is 11. Both are greater than 8. Uh which means that we can we can terminate
41:42:47
over here. So that concludes that at this position five we ran out of the possibilities. We went up at this
41:42:55
position we are done. So again we go back we go back at zero position. We
41:43:00
check that have we any do we have any other options uh where we can explore
41:43:05
and yes currently we are at value number six. So six is again less than our target eight. So we can go further from
41:43:13
six. The thing is at six we can only do 6 six. We can't do any other combination
41:43:19
because those we have already checked so far which means that 6 six the value is
41:43:24
12. So 12 is already greater than 8 which means that we can't go further from this which means we can't go
41:43:31
further. We go back uh at six we see that have we explored all the possibilities? Yes we have explored all
41:43:37
the possibilities which means again we go back to this position zero. So at this position zero we check that now
41:43:44
have we explored all the possibilities? Yes. Initially we check all the possibilities for the value two. Again
41:43:49
we check for value five and again we check for value number six. which means that even at zeroth position we are
41:43:55
done. So our base case has satisfied. Now whatever we have stored in our result parameter result list so far we
41:44:03
can simply return this and this would be our final solution and this is actually
41:44:10
the optimal solution that we can achieve. Notice over here that we are doing lot
41:44:16
of repetitive work at any position. We were calculating the different uh possibilities we can have. We are
41:44:22
picking a possibility. We are exploring in uh that direction depth first search.
41:44:28
Uh we kept on exploring. Once we found a terminating case, Once we found a ter
41:44:35
Once we found a terminating case, we would go back to a point where we can
41:44:41
still explore for more possibilities over here. Again, we would further go down uh to additional possibilities. We
41:44:49
would find a terminating case. Again, we would come back and eventually we would come back to the zero position from
41:44:56
where we started. And uh after the calculation we will return our return result.
41:45:03
So this at any point we are coming back from
41:45:08
where we originally started. This is actually called backtracking. This is a really important concept in uh computing
41:45:16
uh computer programming and uh I just showed you that how can we
41:45:22
use it and that is why because this concept is really important. It has lot of u very practical applications and
41:45:30
that's why you see that why all those big companies like Google, Facebook, Amazon, uh Goldman Sachs they were
41:45:38
interested in asking this question to their inter uh to their candidates because they want to know that are you familiarized with the very important
41:45:45
things that are really critical and uh can you go down that path and uh yeah so
41:45:52
since we have found our optimal solution I did not mention explicitly that I was
41:45:57
showing you the optimal solution. But the thing is I told you that this is the intuition behind it. And once we knew
41:46:03
the intuition, we just need to find a way to implement it in computer programming. The way to implement this,
41:46:11
you must have guessed it correctly that we were doing so some so much repetitive
41:46:16
work again and again and we were using it somewhere and we had some terminating
41:46:22
uh conditions that either if the value is equal to or greater than our target we would terminate which means that we
41:46:28
were using a recursion at uh it its best uh over here.
41:46:35
So yeah this is basically our solution. So let's calculate the time and space
41:46:42
complexity. The uh time complexity for this one would be big of n to the power
41:46:48
t. Now first let's determine that what this n and t means. N is actually the
41:46:54
number of uh candidates uh the least value for this one and T is
41:47:02
actually uh the total amount because imagine that what is what could be the
41:47:08
longest sequence we can have at any given position. Well, suppose our target
41:47:15
value is 8 and our candidate candidate is 1. Which means that we would do 1 + 1
41:47:20
+ 1 up until eight times till we get the value 8. Which means that we need to go
41:47:26
in one direction eight times and at any position we can have multiple options or
41:47:32
we can make multiple decisions and from further down we can go ahead. Which means that we need to do this work n to
41:47:39
the power t times until we find the solution. So that's that's why this is the time
41:47:46
complexity. So first of all we'll create our result
41:47:52
list and now we'll create a list to store the
41:47:58
current combination. Okay. Now uh we will create a backtrack
41:48:03
method and uh in this would be our recursive method. So initially we are
41:48:09
going to provide the target uh result combination
41:48:16
uh zero as the starting point and the candidates array
41:48:24
and uh after whatever the result we get back from the uh recursive call we
41:48:30
simply need to return whatever we find in this result list. So let's create the recursion method.
41:48:44
Okay. So first of all we are going to create the terminating cases. So if
41:48:50
uh target is equal to zero which means that we have find a combination that
41:48:56
sums up to the target value. So we can just simply return it to uh simply we
41:49:01
can simply add the combination to our result.
41:49:23
If this is not the case, we need to return uh we need to check that whether
41:49:29
the target is uh less than zero which means that we
41:49:36
have already surpassed our uh target and we need to break uh so we can just
41:49:42
return null
41:49:47
if both cases are not true which means We still need to look for our combination. So,
41:49:56
uh we'll start by checking in our combination from the position start and
41:50:01
we will go until we still have candidates.
41:50:10
Now, inside the loop, first of all, we will add whatever candidate we are currently looking for in the our combination list.
41:50:26
Okay, after that uh we can do our uh
41:50:32
recursive call
41:50:39
and as a target we will have target minus whatever candidate value we
41:50:55
and start would be I position
41:51:02
and I think that that would be it. Uh yeah, one more thing we will have to remove the entry from our combination
41:51:08
list because we will be doing backtracking when we uh move towards the next value.
41:51:19
And I think I think this would be it. Let's try to run the code.
41:51:26
This should have worked but I don't know why it's not working. So we'll just enter the value manually.
41:51:34
Oh, it should be candidates. Okay, our solution seems to be working.
41:51:40
Let's try to submit the code. And yeah, our solution works uh perfectly fine.
41:51:45
And I will be posting this uh code in the comments. You can check it out from there.
41:52:00
Now we are going to be doing an awesome late code problem that is called combination sum 2. This is the
41:52:06
subsequent question to to our original combination sum problem with some slight tweaks. Now we can see that this one is
41:52:13
a lead code medium problem but in my opinion this can be categorized as hard problem sometimes as well because
41:52:19
combination sum in itself is slightly tricky to understand. And we can see that this one is a very very very
41:52:25
popular lead code problem also being asked at tons of companies. Basically we are given a collection of numbers called
41:52:32
candidates and we are given a target number. Now we need to find all the unique combinations in the given input
41:52:40
array such that the sum of those values is equivalent to the target value. There
41:52:45
can be more than one results. So we need to consider all of them. Now we are told
41:52:50
that each number in candidates may only be used once in the combination and we
41:52:57
need to make sure that the given solution set must not contain any duplicate combinations. Okay. So now
41:53:03
let's first try to understand this with an example. We are given this candidate array and we are given the target value
41:53:10
to be five. Now next thing is that we need to generate the unique sets. Now let's see that what are all the
41:53:16
combinations that can generate this value five. We can see that we have value four and we have value one. So
41:53:22
four and one is a combination that can sum up to value number five. So that this can be one of the potential
41:53:28
answers. Next one is we have value 2 1 and two. So once again we can generate value like this and this can also be an
41:53:35
answer. Next value is that we can do 322. This is also one of the subset that
41:53:41
can generate the answer. But now there is one tra one problem over here. We also have this three that we can utilize
41:53:49
with this two to once again generate the target value five. The thing is that value is also going to be 32 which we
41:53:56
have already entered in our result. So we should not be reusing the same set in
41:54:02
our results because we need to make sure that this answer becomes unique. So if we by considering these elements we can
41:54:09
only generate these three values or these three sets that combination to the
41:54:14
total value five. So we need to understand that this is how we need to solve the problem. So now let's try to
41:54:22
see that what could be the potential solution over here. Now the logically the very first thing that it would make
41:54:29
sense us for us to do is that instead of treating all of these weird values side
41:54:35
by side randomly it would make much more sense to number one sort the given input
41:54:41
array. Why am I suggesting to sorting the given input array? That has two reasons. Number one reason is that let's
41:54:48
say that we have some values like let's say 10 and 15 and then so on and so forth like 100 other values. Okay. and
41:54:54
we are given the target value to be five. So the moment we reach to a value
41:55:00
10 then why do we even have to check possibility for all of these 100 values if we have already sorted the results we
41:55:06
know that all the values sum is always going to be greater than five which means it is going to be shortening the
41:55:12
reach we will have to search for that is a good benefit second benefit is that it will allow us to handle the duplicates
41:55:19
in a more elegant manner so what I'm suggesting is that let's say that in this case we have the values 1 2 2 3 and
41:55:26
four This is the input we are given. Now what we are doing is that logically it's
41:55:32
very simple. We are just simply making decisions. And what is the decision we are making? We are iterating over the
41:55:38
very first element. Okay. So let's say that we are currently passing through value number one. We know that the
41:55:43
target has to be five. But our current sum that we have made so far is just value number one. So we will need to add
41:55:50
some some more subsequent values. So let's say we decide to add value number two down this current path. So now the
41:55:56
sum is three still less than five. So once again we decide to add value number two. So after adding this value our sum
41:56:04
becomes five. So the moment our sum becomes five. Whatever the values we were currently having as part of our
41:56:11
path this is one of the potential answers. So let's mark this as part of the answer. Okay that we currently have
41:56:19
have found one of the combination 1 to2 as part of the answer. After doing this, there is still more possibility that we
41:56:26
could have some other value that we might have missed on. So we will have to backtrack and once again see for other
41:56:33
possible answers. So let's say that we do a backtrack at this position number two and once again um this now the now
41:56:41
the problem comes because this next element is already two and we just did a backtrack. But the thing is we already
41:56:48
considered this two. So now we will have to consider value number three. Okay. So let's say if we try to do this one this
41:56:53
current sum becomes six. So the moment current sum becomes six we know that this is no longer a viable solution
41:56:58
which means we will have to do a backtrack because this solution is leading to a value greater than five.
41:57:04
And once again we will have to repeat the operation for all the other remaining possibilities. So we remove
41:57:10
value number two. So once again now with this value number one there might be some other solution with one and three
41:57:16
that we could make. So we try to add value number three. After this value number three, the current value is four.
41:57:23
After four, we add value number four over here. So doing this also brings us brings our sum greater than five. Which
41:57:29
means we will have to do a backtrack. We do a backtrack and we get rid of this value number three. Now at this value
41:57:36
number one, we still have possibility to check for value number four. There is still one more decision we haven't made. So let's say we do this one. The sum of
41:57:42
this is actually five which means we found another set that corresponds to our correct result and our correct
41:57:48
instinct. So we are going to mark this as part of the answer as well. Now once again we know that we took care of all
41:57:56
the things we could using this value number one. So now we are simply going to go to the next element and not even
41:58:02
consider one because we ran through all the possibilities we could with value number one. So we don't have to worry
41:58:08
about it. Now at this value number two let's say let me just clean this up a bit. Now we are making a new decision
41:58:15
tree a new decision path where we have two once again we go to the next element
41:58:20
that is once again two. After doing this we go to the next element that is three.
41:58:26
So now this sum in total becomes seven. So 7 is greater than five. If 7 is greater than five going down this path
41:58:32
two does not make sense. So we are going to ignore that. Ignoring this we now we
41:58:38
are going to be going with three. So we have we are at this juncture and we
41:58:44
found that current sum is five which means this is one more potential answer that we will have to record. So let's
41:58:50
mark this one. Okay marking this we are not done yet because we will still we
41:58:55
may still find another results we don't know. So we go to this next element 2 to
41:59:00
four. But this also leads to result number six. Which means we calculated all the possibility at this current two
41:59:07
as being the very first element where we are calculating. Now the thing is next
41:59:12
element is also value number two. And we can see that with previous element two
41:59:18
we already calculated all the possibilities. So if we had a target value let's say in instead of over the
41:59:24
over here instead of five if we had a target value four we would have a potential value 22 that is being
41:59:31
generated by this two already. So we don't have to do anything over here and also if we try to go down this path
41:59:38
let's say that we ignore my advice for now and we say that currently we took
41:59:44
care of this one we took care of this two this two is still valid and legitimate. So now we have this value
41:59:50
number two. Once again we go down to the path. So we find value number three as the next potential match and this
41:59:56
matches. So should I add it to the answer? No. Why should I add it? Because I already calculated this one. So what
42:00:03
I'm suggesting is that once we have the sorted list, we simply check that for
42:00:09
any particular element that we are trying to iterate over in the recursive manner using our backtrack function and
42:00:15
recursive function. we first check that whether if it is the same element as the previous element. If that is the case,
42:00:20
we already already calculated all the possibilities and add it to our answer. So we can simply ignore that. So now we
42:00:27
we are going to be ignoring this three as well. Now we are left with this element number three. So let's try to
42:00:32
make possibilities with this three and we are just going in one direction. We are not going in the opposite direction
42:00:38
because we calculated all the possibilities. So with this three, the only possibility we have is to add value
42:00:43
number four. The sum is going to be seven. So greater than four which means this leads to no result. So we already
42:00:48
calculated all the possibility is three as well. Next is the only element four. Once again if we calculate the
42:00:54
possibility uh there is only going to be just element number four which is not five. So we cannot put it in the answer.
42:01:01
After this we are done with all the elements in our input and this is the answer we need to return. So now let's
42:01:08
do a quick recap what we did. We calculated that what was the backtracking function and we also
42:01:14
calculated that what is going to be a recursive approach. For recursive approach we need to add items. We need a
42:01:20
base case and we need a uh recursive call or recursive function. We know that
42:01:26
what is going to be our backtracking logic that at every possibility the
42:01:31
moment we either reach to uh the target value is equal to five or target being greater than five. In either case we are
42:01:38
e if it is five we are going to be adding it to the answer. If it is greater than five then we are going to
42:01:43
be going to the very previous element that we were iterating over and remove that from our current list and follow
42:01:50
along with the remaining possibilities. That is option number one for our recursive. The logic is quite
42:01:55
straightforward. Base case is going to be that uh the total sum of the current elements that we are iterating over it's
42:02:01
either five or greater than five. If that is if it is equal to five, we add it to the answer. If it is greater than
42:02:08
five, then we can simply just move forward or jump to the next element. Uh and for the recursive function, we are
42:02:14
simply going to go in a normal u normal fashion by adding the current value and
42:02:20
removing the current value from the given input array and just calling making a recursive call by adding a new
42:02:27
value that is next inside our given array. So if we see the coding solution it would make much more sense and this
42:02:34
is in my opinion a very beautiful solution. So I hope you understood what I was trying to explain. Now let's
42:02:40
quickly see the coding solution for this one. So here is the coding solution. First of all we are generating our
42:02:46
result where we are going to be storing the list of array list. Then we are sorting the given candidates array. Plus
42:02:53
we are have we are going to have our backtrack recursive method where we are going to be back doing backtracking and
42:02:59
also making recursive calls. So now let's understand our backtrack method. So first we are passing in the result
42:03:05
list that we just created. We are also maintaining a current list. We are also maintaining the candidates array that we
42:03:11
are iterating over. On top of it we are we have provided our target and we have provided our start values. Okay. First
42:03:19
very first thing we are doing is checking that if the given target is equal to zero then we are going to be adding the current list uh inside our
42:03:25
result and we are simply going to do a return uh from our current recursive call. If that is not the case we will
42:03:32
run our for loop where we are simply going to iterate over all the values that are currently present inside the
42:03:37
candidate. Very first thing we are doing is skipping the duplicates. So we are checking that if the current candidate
42:03:43
is same as the previous candidate we can simply ignore that value. Next, we are also doing an early uh termination if
42:03:50
the sum becomes negative because at every given moment, the moment we see a
42:03:55
new i value, we subtract that i value from the given current target element
42:04:01
and uh the moment we realize that this is going in into the negative, we are simply doing a break operation. Now, if
42:04:07
that is not the case, we add the current value to our current array list that we are maintaining. Then we once again make
42:04:14
a recursive call with the current value which contains one more value right now
42:04:20
and we provide the target minus candidates I because we are subtracting the value from the target that we need
42:04:26
to achieve and we update it with the next element inside our for loop and that's it. Now once we get a result back
42:04:33
from our backtrack we simply remove the very last element and we once again do
42:04:38
uh the same operation for other possibilities that we are yet to calculate. So this should this approach
42:04:44
should work. Now let's try to run this code.
42:04:51
Okay, seems like our solution is working as expected. Let's submit this code.
42:04:59
And our code runs pretty fast compared to lot of other solutions which is pretty good. So once again I will be
42:05:04
posting this solution in our GitHub repository. So you can go and check it out from there. Thank you.
42:05:23
So the lead code problem we are going to solve now is called palindrome partitioning. We can see that this one is a medium problem but in my opinion
42:05:30
this should have been a hard problem. We can see that this is a very well-like problem. Now let's understand that what
42:05:35
is being asked us to do. We are given a string S and we need to partition this
42:05:41
string S such that that every single substring of that particular partition
42:05:48
becomes a palendrome and we need to return all possible palendrome partitionings of S. So it sounds a
42:05:56
little bit awkward but let's try to understand this with an example. First let's understand that suppose we are given a string S such that the values
42:06:03
are a b c. So we can see that in this case uh if we have to partition string there are bunch of different options. We
42:06:09
can have a partition that is completely like this or we can do a partition like a b and c or we can do a partition like
42:06:16
a and bc something like this one right there are bunch of different ways for us to partition any given string. The thing
42:06:21
is in this case we need to find partitions such that every single
42:06:27
partition becomes a palendrome. Now we all know that what is the definition of a palindrome. Suppose we are given a
42:06:34
value like this aba. In this case this aba is a complete palendrome. Why? Because if we write it from left to
42:06:40
right or right to left in both the cases the answer is just going to be aba. So
42:06:46
same way this uh let's say if this is the input we are given and if we have to partition it in such a manner that every
42:06:53
single substring of that partition becomes a palendrome we only have one possibility. That possibility is if we
42:06:59
partition it used by using just individual characters because an individual character in itself is a
42:07:06
palendrome because uh let's say if we only have one value you can read it from left to right or right to left in both
42:07:12
the cases we are going to be left with the same value. So this is the only answer we need to return in this case.
42:07:18
But let's say that we may have been given some other options. Let's say that our given string s is equal to values
42:07:25
such as a then a and b. Okay. Uh
42:07:34
let's say our given string s is equal to values a a and b. So now in this case we
42:07:39
we will have two options in order to generate the partition. First partition is going to be quite straightforward
42:07:45
that is taking on individual characters because they are palendrome and their own and combination of these characters
42:07:52
actually form in such a manner that every single character is a palendrome in itself. But we can make one more
42:07:59
distinction or one more answer in this case where if we create a partition of these two values a a as one partition
42:08:06
and we create another partition of this individual character B then also this becomes a valid partition of the
42:08:13
substring such that every single portion of the partition actually forms a
42:08:19
palendrome because this a a is a palendrome and this b is a palendrome in itself. So this is what the problem
42:08:25
statement is actually asking us to solve. Now let's try to understand some logic on how we can actually solve this
42:08:32
problem. Uh well if we just have to solve it using pen and paper. What is
42:08:37
going to be the first logic you are going to apply? Well, the very first logic is that we will start iterating
42:08:43
over this given string character by character comparing every single
42:08:48
character with the previous characters that we have we have been able to find so far to determine that whether using
42:08:55
the combination of previous characters are we able to generate palindrome or not if we are able to generate a
42:09:00
palendrome we would mark it as one of the partition and then we will keep on moving forward so let's try to
42:09:07
understand the approach I'm suggesting let's Say over here we start iterating over at this very first element A. Now
42:09:13
for this very first element A the moment we come to this element A we have two choices. One choice is that A in itself
42:09:20
could be a palendrome. So we mark A as a palindrome and same way there could be
42:09:26
another possibility that we may find some value where this A could be potentially part of some future
42:09:32
palendrome that we are yet to discover. So let's leave this possibility open for
42:09:37
us uh for the moment. Okay. Now if we decide to create a partition based on a
42:09:43
then once again we have the option to move forward with a single a or the next element. So let's say that once again we
42:09:49
decide to move in with a single a and create another partition which this is the first partition and this is the
42:09:56
second partition. Okay. And uh once again we move to the another value and
42:10:01
for this next value we encounter value B. So once again we create a partition in its own. Now the thing is when we
42:10:07
reach to this B we realize that now we have reached to the end of our array. So
42:10:12
far all the values we find inside or all the partitions we did for our given
42:10:18
string s all of these values are palendromes because let's say that in order to determine that whether any
42:10:25
particular string is a palendrome or not we are actually going to create a method that checks that if the given string is
42:10:31
a valid palendrome or not. Okay. And this string is quite straightforward. They are the values of itself. So we
42:10:38
know that all of these values are correct palendromes. And we are also storing some current array list where we
42:10:44
are keeping track of all the current values that we are iterating over one by one. So we realize that this is the
42:10:50
correct sequence of partition that generates a palendrome. So we are going
42:10:56
to mark this option inside as part of our answer. After marking this, we we
42:11:02
are not done yet because once again I mentioned that there could be some potential ways or some potential other
42:11:09
uh paths that we are able to generate which could lead us to more palendromes that we are yet to discover. So once
42:11:16
again let's try to apply that same logic in this case. So now once again we
42:11:22
already explored this path. Okay. Now what we are going to do is we will do a backtrack operation once again to the
42:11:28
very first character to make sure that maybe we did not miss out some palendromes that we could have found. So
42:11:34
let's say that we instead of just creating a single value partition from this single value we actually decide to
42:11:41
do a partition of two values. So creating a partition of two values would give us value a a once again we check
42:11:47
that if the is this a valid palendrome or not and yes this is a valid valid palendrome. So we are good to continue
42:11:54
to the next element. For some reason if we identified that this was not a correct palendrome. Let's say for some
42:12:00
reason that this value given is x. So then this ax is not a correct palendrome. If this is not a correct
42:12:06
palendrome then it does not make sense for us to continue down this path of partitioning. So then we would choose a
42:12:14
different path where after this ax we would actually include b in our decision
42:12:19
making as well. But that is there is no need to do that. So let's leave it as it is right now. So after leaving it as it
42:12:26
is. Okay. So we created another partition at this moment. A a the answer is valid legitimate. So we are keeping
42:12:32
it as it is. After keeping this as it is now we decide to go to make another
42:12:38
partition that is this value B. So once again we create a single partition of just one value B. This is also a
42:12:44
palendrome. And with this B we reach to the end of our list. So after reaching to the end of our list, we are also
42:12:51
going to be marking this uh sequence that we found as part of the answer as well. Now let's try to clean this up a
42:12:57
bit. And now once again we will we are yet to explore more possibilities that we haven't found. So we will also try to
42:13:04
do this one. Now for the more initially we took down a possibility where we are only partitioning the string based on
42:13:09
just one value. Then we partitioning partitioned the string by using values a a and then also it worked out. Now we
42:13:18
are going to partition the string based on considering all three values. So let's say that we just create a
42:13:24
partition that is a a and b. This become this is definitely not a palendrome plus
42:13:29
we reach to the end of our list. So now we are done with our search with
42:13:35
starting all the possibilities from this current value a. Now we are yet to identified more possible palendromes
42:13:43
that we are yet to identify. So let's say that in the very first beginning when we made this partition now we will
42:13:49
continue down this path but previously we went down this path uh that was this
42:13:55
answer over here. Now we will try to choose a different path and in this different path what we are going to do
42:14:00
is with this a now we are going to pass the button onto the next element and now
42:14:06
we will say that hey next element if you want to do or try some partitions let's check those. So once again from this A
42:14:13
we can create another partition like AB but definitely this partition is not a
42:14:18
palendrome. So if this is not a palendrome then it does not make sense for us to continue down this path and
42:14:24
anyways we are running out of elements in this case. But let's say if we had some more elements over here let's say
42:14:29
some more element like C. So do you think it would make sense for us to create a partition such that A B and
42:14:36
next element to C check like this? No. because we already know that this is not a sub palendroic sub uh substring. So
42:14:43
why even bother checking? So then in that case our logical step would be to include C as part of one of the
42:14:50
possibilities as well. But once again this is also not palendrome. So now we can be done with this. So this is the
42:14:57
simplest approach we can take to solve this problem. Now we all know that what
42:15:02
we did we use the backtracking option to basically uh go through go through all
42:15:09
the possibilities that we can in order to generate or find sufficient answer. Now let's try to understand that what
42:15:15
has to be the logic of our backtracking function. This is going to be a simple function that uh takes the current
42:15:22
partition that we are dealing with and based on the partition from the input
42:15:27
string it is going to have a starting index for the next partition that we are going to check with and with the uh
42:15:35
starting index of the next value. We should be able to understand that are we at the end of our uh string or not and
42:15:41
whether we can conclude the current partition to be over or not. on top of it with every single value we are going
42:15:48
to check for any particular uh substring that we are generating that whether that
42:15:53
is a palendrome or not and in order to do that in order to accomplish all of this we will actually use recursion. Now
42:16:00
for recursion we know that we have two items that we need first one is a base case and second one is a recursive
42:16:06
function. base case is quite straightforward that if we I previously mentioned that we are going to have a
42:16:13
variable called start to keep track of the next index that would be the starting point of the next sequence of
42:16:19
palent rooms. Let's say that we created a subsequence like this a a one of the palendrome then start index would be
42:16:26
living over here with value number two as that is the logical starting position. So we are going to check that
42:16:32
if for the current list we come to a place where the starting index is the
42:16:38
length of the given string then we are going to be marking that current index as part of the answer and returning or
42:16:44
coming back through a recursion. So we identified our base case for the recursive function we will have to do
42:16:50
two things. First thing is that for every single new partition we make we
42:16:56
will have to check that whether this is this one is a valid palendrome or not. If let's say that that is a valid valid
42:17:02
palendrome then it would make sense for us to call the recursive function once
42:17:07
again with the next value in line and creating the current partition as it is.
42:17:13
Now I know it sounds confusing but if you just understand that or try to walk over the solution that I presented then
42:17:20
it would make absolutely beautiful sense to you that what I'm suggesting and on top of it uh for the recursive function
42:17:27
we are also going to be updating the current index value that we are iterating over let's say that we
42:17:33
iterated over a a so then we will have a recursive function starting with value number b and once again we will try to
42:17:39
repeat the same process combination of all of this should will give us the answer. But thing is this is not just
42:17:45
enough. Once we receive a call back and we will have to check for other possibilities where first we check for
42:17:52
the possibility of a only then we may have to check for the possibility of a a. So in order to do that we will have
42:17:58
to do a backtrack and for the backtrack the simplest thing is to remove the very last element we added inside our current
42:18:05
array or current array list and once again repeat the same operation. So basically combination of backtracking
42:18:11
and recursion is the way to move forward in this case. Now let's try to calculate
42:18:16
the time and space complexity. Well time complexity is difficult and tricky to calculate in this case because we don't
42:18:22
know that how many number of potential partitions we can make. So at the end of the day this is simply a decision making
42:18:30
algorithm and in the decision-m algorithm at every given step let's say that we created a partition like this A.
42:18:37
Now we will have to check whether to include this A or not to include this A as part of the partition. So at every
42:18:43
given step we are checking for or to whether to make that decision or not to make that decision. So basically we have
42:18:50
2 to the power of n possibilities where n is the number of characters to given and for every single character we will
42:18:57
have to repeat the same operation. So it's going to be n multiplied by 2 ^ of n possibility. And that's why this is a
42:19:03
very expensive operation. And uh if you go through the lead core problem, we are all we are only given like up to from 1
42:19:11
to 16 as part of the range of n uh for the length of the string because they
42:19:16
also realize that they don't want to put much load on the lead code servers. So now let's try to quickly see the coding
42:19:22
solution for this one. Okay. So the very first thing we are doing is that we are
42:19:27
generating a new result array list that is going to store different array list
42:19:32
inside it uh to store our answers. Then we are going to have our backtrack method where we are passing in B first
42:19:40
of all the result array list we created. Then we are also passing in the current list we are iterating over passing in
42:19:46
the given string that we are given as the input and we are passing in the starting value of the next pointer that
42:19:52
we should uh consider for the partitioning. This is the starting pointer that I just mentioned. Okay. Now
42:19:59
first of all let's see in our recursive function we are going to have our base case where we are first checking that if
42:20:04
the starting value is the length of the given string which means we are actually reach to the end of the string. So we
42:20:11
can add the current result we are iterating over inside our result array list and we can simply do a return call
42:20:18
from the iterative stack. And now let's check check our recursive case or
42:20:24
recursive function. So for that we are in we are basically iterating over from the starting index till the end of this
42:20:31
list and we are updating the value and here I mentioned starting and ending pointer. This is just simply so that we
42:20:37
can check that the given palendrome or the given sequence of element uh partition we are iterating over if that
42:20:43
is a substring or not we can simply make that call. So first thing we are going to check is that if the given current
42:20:50
substring is it a palendrome or not. For that we have created is palendrome method where we are doing nothing but we
42:20:56
are simply iterating over from both ends like starting pointer and ending pointer. If at any given moment we
42:21:02
identify that they both there is a mismatch we simply return false. If that is not the case and we complete the
42:21:08
whole uh iteration then we can simply return true saying that this current substring is a palendrome. Okay. After
42:21:15
determining that the current set of partition is a palendrome. We are going to add that substring to our uh current
42:21:23
list that we are maintaining. And once again we are going to recursively make call by with the same values except the
42:21:31
next index position that we will have to iterate over and that is going to be our end + one. You can also define this end
42:21:38
instead of end to be I as well. I just put in end for it so that it becomes
42:21:43
better readable for our isalendrome method. And once we get a result back
42:21:50
from our backtrack method, we are simply eliminating the last value we inserted inside our current list because we still
42:21:56
have to explore more possibilities. And this is our backtrack uh function basically. So now let's try to run this
42:22:02
code.
42:22:10
Okay, seems like our solution is working as expected. Let's submit this code.
42:22:18
And our code runs pretty fast compared to 98% of all the other solutions which
42:22:23
is exceptionally good. Once again the solution on of this code is presented on our GitHub repository. So you can go and
42:22:30
check it out from there. Thank you.
42:22:46
Okay. So now we will attempt to do a very scary question that is called n queens. Now in my opinion this is one of
42:22:53
the most toughest and most interesting problem I have seen. Uh basically this one is a lead code hard problem and very
42:23:00
justifiably. Uh it is also an extremely well-like problem. And let's understand the statement. The n queen puzzle is a
42:23:08
problem of placing n queens on an n crossn chessboard. So if if we are given
42:23:14
let's say 4x4 chess board, we will have to place four different queens. Now we know that every single queen can iterate
42:23:21
in three directions. Let's say that if I decide to place a queen over here, then this queen can control these squares,
42:23:28
these squares and these squares because queens iterate in all three directions.
42:23:33
So based on considering a formation such that that I am able to place four
42:23:39
different queens and without these queens intersecting with each other on a
42:23:44
given n cross n board and I will have to make sure that I populate all the n queens. Now let's see that what else is
42:23:51
being asked for this problem statement that uh we are being told that we are given an integer n that defines that
42:23:58
what is going to be the size of the board we are dealing with. Now we need to return all the distinct solutions to
42:24:04
the n queen's puzzles. And good thing for us that we can return the answer in any order. Now there is also one more um
42:24:12
just a quick note that each solution contains a distinct board configuration on a place where the queens can be
42:24:19
placed. Let's say that if I decide to place a queen over here, then next queen might be placed somewhere over here
42:24:25
because I need to avoid uh hits by this queen. So there can be one of one
42:24:31
solution or two solutions or three solutions. No matter how many solutions are there where I can place all four
42:24:36
queens on this four cross four board I will have to put all of those solutions
42:24:42
inside the answer. Next thing is uh we are being told that where we are placing
42:24:48
the queen we will mark it as cube and where we are not placing a queen we will just mark it with a dot. So let's first
42:24:55
try to understand this problem with this given example of a 4 + 4 board. The idea is we are trying to place four different
42:25:02
queens on this board and we will have to explore all the possibilities we could in order to generate the answer. Now
42:25:09
this is going to be a very long video. So I'm just warning you beforehand. I don't want to take any shortcuts and I
42:25:14
want to make sure that I understand this problem and you understand this problem. So now let's get started. Uh basically
42:25:20
let's start one by one. Let's say that I put the first queen naively on this very first location. If I do that, which
42:25:27
means essentially I'm eliminating all of these squares for any other queen to
42:25:34
pursue or and use it as for their configuration. Let's say I do I put this
42:25:39
queen. Now in order to put the second queen, I have two options. So let's say randomly I just pick this option. Okay.
42:25:45
So once again after picking this option also these squares are now being controlled by this queen. Uh next thing
42:25:52
is if I want to put another queen there is no place for me to put the third queen because this entire row has been
42:25:59
covered because I put this queen over here. So let's try to revert that. Let me try to put this queen somewhere else.
42:26:06
Okay. So let's say if I don't put this queen over here then uh all of these
42:26:11
squares would become empty. And once again let me just try to put this queen on the second position and then try to
42:26:18
see. So let's say if I put this queen over here once again these squares gets controlled by this given queen. And now
42:26:25
I only have one option in order to put the third queen. So I can put third queen over here. But that controls this
42:26:32
option which means once again I cannot put four queens over here. So once again I will have to go back and go back. I
42:26:39
exhausted all the possibilities for the second row which means I still have to ex uh exhaust more possibilities at the
42:26:46
first row by changing the position of this queen. So let's try to do that operation. For that I'll have to clear the board and basically do a backtrack
42:26:53
operation. Let's do that. And now I'm trying to place queen over here. Now
42:26:58
which are the squares being controlled? Let me just quickly mark each one of these to make sure that I don't uh
42:27:04
create any confusions. Now for the second row, I only have one possibility where I can place my queen. So let me do
42:27:10
that. And let me also mark all the items that are being impacted by this queen.
42:27:16
Okay. Now for the third row, I only have one option. So let me also place one queen over here and once again exhaust
42:27:23
all the possibilities. And now for the fourth row, I only have one choice where I can place the queen and that is this
42:27:29
empty square. So now we can see in this case that we are able to place all four queens on a four cross 4 + 4 grid. So
42:27:36
this is one of the potential solutions. So we will actually have to mark this entire solution and place it inside our
42:27:43
answer array. So the thing is let's say that we create a list of list that is going to store all the answers. uh how
42:27:49
we are going to take the snapshot of this is that we are actually going to create an array that is going to
42:27:55
represent every single row for this given entire section and for each of the
42:28:02
row we are going to mark it as this that we are going to store string values where for the first two elements we
42:28:07
don't have a queen so we are going to mark them by dots and then we do have a queen so we are going to mark it by queen and then we are once again going
42:28:14
to mark it by dot once again we are going to it do the same process so queen and then dot dot dot. Once again for the
42:28:21
next element repeat the same process. So basically three dots and then a queen. And for the last one we are going to dot
42:28:28
queen and dot dot. So uh dot queen and dot dot. Okay. And so this becomes one
42:28:35
of our answers. But I think is this is not the whole answer. We could still have more potential answers. So let's
42:28:41
say we explored one possibility. Let's try to explore another possibility. And remember once again we are doing the
42:28:46
backtrack operation going back to the very initial call. We already exhausted these two possibilities for the position
42:28:52
of queen. So let's try to explore more parts. Let's say if queen is over here then once again let's repeat the same
42:28:59
operation. We are going to eliminate all the squares being controlled by this queen. The option is to place it over
42:29:05
here. Once again eliminate all the options. Once again we can place a queen over here. And for the last one, we can
42:29:13
place a queen on this position. So once again, this becomes another one of distinct answer because notice the
42:29:19
positioning of queens are different compared to our previous answer. So once again, we are going to note this entire
42:29:25
answer. Now don't worry, I will not put you through the painful process of going through the whole thing. Let's say that
42:29:30
I just paste this answer over here uh as part of the next array list inside our
42:29:36
answer where we are going to return the list of array list. Okay. And now let's
42:29:41
say we we try to explore the very last option for the queens. Once again for the very last option we are going to be
42:29:48
placing the queen over here. If we try to do this one basically this solution would not work because uh we would not
42:29:55
be able to find appropriate queen positions in order to fill it out. So notice that in this case once again we
42:30:02
filled out all these four possibilities because we placed a queen over here. If we don't do that, if we decide to place
42:30:08
a queen over here, then once again we are eventually going to fill out all of these possibilities. So these are the
42:30:13
only two distinct ways through which we can place all four queens on this four across four grid and this is what we
42:30:20
will have to return as part of the answer. So this is what is being asked us to solve. Now the thing is uh let's
42:30:29
see how we can actually solve this problem. So notice at the very beginning when I selected a queen over here
42:30:36
immediately I did not started rejecting this option. Basically what we can do is
42:30:42
that at every single position we have two options to make that whether we can
42:30:47
place a queen over there or we cannot place a queen over there. Now we will have to explore both the possibilities
42:30:54
and in this case we will proceed in column by column area. So we will try to
42:31:00
put the queen on the first column. Based on that we will it would determine the position of the second column and then
42:31:06
third column and then fourth column. So initially the idea is going to be that for the very first column on the
42:31:12
leftmost portion or the very first value we will try to place queen. And let's
42:31:17
say that after placing this queen, our logic would be that we will have to find
42:31:23
an empty space in this particular section where the squares are not being
42:31:29
hampered by this queen. We can completely ignore this entire column. the moment we place queen at one of the
42:31:35
position. So our jumping is going to be based on column by column level and at
42:31:40
every single column for all the n values we will have to determine that whether it is a a sufficient place to place a
42:31:48
queen and the moment we find the very first opportunistic moment where we can actually place the queen. Once again we
42:31:54
are going to repeat the same operation for the next subsequent column and once again we will try to find an appropriate
42:32:01
cell where we can actually place the queen. So there would there could be two options. One option is that let's say
42:32:08
that we are able to identify some place where uh in if we just take a look at
42:32:14
this example basically in this example if I place a queen over here we we
42:32:20
exhaust all the possibilities. Now there are no place for us to place a queen which means immediately it should come
42:32:26
to our brain and also in our program that placing queen over here is not a
42:32:32
good idea. That is option number one. Option number two is that placing queen over here is not a good idea. So we are
42:32:38
going to do the backtrack operation and after backtracking we will first try to remediate our this uh uh mistake and we
42:32:46
would instead of placing queen we would place at the second possible place and once again try to repeat the same
42:32:52
operation. But eventually this will also not yield us the correct result. And eventually we would keep on backtracking
42:32:58
to our very first decision. And through the very first decision we would try to make sure that okay instead of placing
42:33:05
the queen over here let's try to explore other possibility and then this would
42:33:10
lead lead us to our correct result. So that is number one thing on we can understand that how we are actually able
42:33:16
to find the answer. The logic is quite straightforward. We are simply going to do a recursive backtracking call in
42:33:24
order to determine that whether the given path is a correct sensible path or not. But this is not as simple as it
42:33:31
sound because there are lot of computation and lot of things we will have to understand and break down for
42:33:36
our program to that how it it is going to work. So let's quickly understand
42:33:41
first that what is the what is going to be the recursion we need to do in this case to complete the problem. Well, we
42:33:48
know that for recursion we need two items. Number one item is that a base case and second item is that we need uh
42:33:54
a appropriate recursive function. Base case in this case is quite straightforward. The moment on the C4th
42:34:02
uh column we find an appropriate location for the queen. We know that we
42:34:07
already crossed all of these uh columns and then we reach to the column 4 where we are able to find an empty slot for a
42:34:14
queen to be put in. So which means this has to be the complete correct path that
42:34:20
we are able to generate in order to fill the answer and that that is exactly what we are going to be storing as part of
42:34:27
our base case. So what we will do is number one we will need some way to keep
42:34:32
track of all the paths that we have taken so far because uh by doing that we
42:34:37
are doing two things. Number one thing is that when we do reach to that happy path scenario for our base case, we can
42:34:44
actually add the path that we have stored for for so long for the positions
42:34:49
of queen as part of the one of the values for the answer. So that is number one thing. Number two thing is that
42:34:55
using this path let's say at some moment we decide that we cannot go further
42:35:02
anyway then once again we can just say that this path does not leave yield to
42:35:07
the correct result. If it does not yield to the correct result we can simply do a backtrack operation and through the
42:35:13
backtrack operation we will try to explore other paths. So just same way we saw over here that this Q location was
42:35:19
not working out. So we tried to see for this Q location once again that didn't work out. So once again we updated from
42:35:26
our Q location this one to this one and then we try to identify that whether
42:35:31
this is the correct path or not. So we made some judgment calls through our
42:35:36
recursive function on what are the things we are trying to achieve. Basically don't get confused. We are
42:35:42
just doing exactly the same thing that I showed you on the through the throughout the entire graph. The only difference is
42:35:48
we are trying to do it recursively and we are trying to follow both the things that what is going to be the base case
42:35:54
where we need to break out of the recursion and store the value to the answer. If we are not able to do that
42:36:00
then we will also have to do the recursion using the correct path we current path we are choosing in order to
42:36:06
solve the problem. Now there are also few more things that we will have to understand. First thing is that at every
42:36:12
given moment whenever we are checking for potential candidates we will have to understand that whether this path we are
42:36:19
taking if that is the correct path or not because let's say that in this case I place a queen over here which means I
42:36:26
am eliminating these elements that can ever be used for the potential queen. So
42:36:31
now when I am at the column two, I once again going to check all of these
42:36:37
positions one by one. And in order to check that whether they are good candidates or bad candidates for my
42:36:43
queen to be placed over here, I will need some method to basically do a validation that whether I can place my
42:36:50
queen on this square or not. And the only way I can check is that that is to check my current path that I have
42:36:57
currently iterated over and see that this particular cell has it being impacted by any of the queens that are
42:37:05
that I have previously placed. And by doing that uh we can actually make sure
42:37:10
and find the potentially good values for our queen. So let's say that we
42:37:16
identified potentially good values for our queen. So we did this operation for this first column. Then once again we
42:37:22
repeated the same operation for this next column. Once again we are going to repeat the same operation for this third column. So logically we are just redoing
42:37:30
the same thing that we have done in the past but for the different input. And that's where the second requirement for
42:37:36
our recursion comes into the place because remember recursion needs two items. First one is a base case and
42:37:42
second one is a recursive function. So as part of the recursive function whenever we are moving to the new column
42:37:48
we are simply updating the value of the column plus we are also updating the value of where we have stored the queen
42:37:54
in the previous value inside our current path. So this will allow us to do the backtrack and also allow us to move to
42:38:02
the next value inside the logical iteration of our recursion on top of it.
42:38:08
That's why this is a hard problem because there are lot of on top of it that you will have to understand. At
42:38:13
every given moment once we reach to the very end in the current path we are not uh keeping track of all the items of the
42:38:20
board. We are just simply keeping track of the position of queen uh that we have
42:38:26
placed so far in each of the columns. So once again we will have to have a method where we are actually generating the
42:38:33
board based on the positioning of the queen. So remember that ugly board that we were seeing like that contains dot q
42:38:40
dot dot then once again like dot dot dot q and this type of like uh more code
42:38:47
type of structure we will also need a method to generate this as well and this
42:38:54
is the solution. Basically this is the optimal solution in order to solve this problem. We are using backtracking we
42:39:01
are using recursion. For recursion, we have a base case. We have a recursive function. We are keeping track of the
42:39:08
current path we are at. We need to have a method to check that whether the given
42:39:13
path is valid or not uh to place the queen based on the previous queens we have placed. Plus, we will need a method
42:39:20
to generate the board that we need to generate in order to solve the problem. And in the end we need to store
42:39:26
everything in an answer where in the answer we are actually storing the bunch of different arrays as part of the array
42:39:34
array. So it's going to be a an array list that contains multiple array list.
42:39:39
And if we see if we try to calculate time and space complexity in this case well it's really difficult to calculate
42:39:45
the time complexity. But let's try to understand the time complexity logic in this case. If you can uh understand this
42:39:52
then your logic to solve time complexity is going to be pretty beautiful. Logic
42:39:57
is quite straightforward that for every single column we are iterating over all
42:40:03
of these values and we are doing it for each of the columns which means basically we are in the worst case
42:40:09
scenario we are iterating over each one of the elements. So basically
42:40:15
uh and the number of elements we know are n to the power two and at every single element we have two choices to
42:40:22
make whether to include that element or not to include that element which means we are actually doing 2 to the power of
42:40:29
n multiplied by n or 2 to the^ of n² work
42:40:34
uh for this one. And we will have to repeat the same operation for each of
42:40:41
the columns because remember that in column one there are four possibilities that can lead us to different parts
42:40:47
which means we will have to calculate this for each one of them. So we will also have to do this operation n times.
42:40:53
So time complexity is horrendously bad and that's why if you read the problem
42:40:58
statement on lead code we are only being told that the value of n can only be between 1 and 9. Nothing more than that.
42:41:04
we are dealing with a very small number of finite solutions because if you try to do this with million values we need
42:41:11
quantum computers in order to solve this problem. Okay. Now let's quickly see the coding solution and I hope my solution
42:41:18
made sense to you. Okay. So the very first thing we are doing is that we are we only have value
42:41:25
n that we need to return. So first of all we are creating a blank board of n cross n size and we are marking all the
42:41:33
values as initially as dots because we don't have any queens placed at the moment. We are also initializing a new
42:41:40
array list of list called result where we are going to be storing all the result and then we are going to be
42:41:46
calling our backtrack method. This backtrack method is going to do the backtracking and also recursive function
42:41:52
for us. In the input, we are providing the new board that we just created plus the starting index of the very first
42:41:59
value that we need to iterate over and the result array list that we have just created in order to store all the
42:42:05
answers. Now let's understand our backtrack method. So very first thing we are doing is uh this is our base case
42:42:12
that if the current length of our column is equal to the length of the board
42:42:17
which means we have place the queens correctly on all four columns or all n
42:42:23
columns. So the correct current path or the current version of board is is subse
42:42:29
is suitable enough for us to place it into the result. But thing is we are not directly placing it into the result. We
42:42:35
are actually calling a construct method to construct the board we want in the subsequent manner. And first let's just
42:42:41
see the construct method. Okay. So in the construct method we are just passing in the board. On top of it we are
42:42:48
checking that what are all the current positions of the queen that we currently
42:42:54
have and we are just adding those values as part of the Q. Apart from that we are
42:43:00
not doing anything else and we are simply returning that to the result. Okay. Next thing is uh so let's say we
42:43:06
add the appropriate result over here. Then we have our for loop which we which allows us to iterate over all the values
42:43:14
inside our given input where we are starting the value from zero. We are going until the length of the board and
42:43:20
we are just doing I++ very beginning for every single board
42:43:25
position. We are checking that is it a valid place where I can place my queen.
42:43:30
And this is valid method is doing nothing but checking that based on the
42:43:35
previous parts that we have calculated whether we have any particular queue or
42:43:40
any particular queen placed before that is either in the row of that particular
42:43:45
queue in the column of that particular que or in the diagonal of that particular queue. If that is the case,
42:43:51
we simply need to return false that this is not a valid position where we can store our queen. If none of these cases
42:43:58
are true, then only we will return true saying that yes, this is a valid place where we can actually place our queen.
42:44:04
So once we find a valid place, we update the position of our board to mark that value as Q or queen. And then once
42:44:12
again, so this is what this we are updating the current path. And then once
42:44:17
again we are going to be calling our current recursive method with the new recursive call where we already updated
42:44:24
the current path of the board. And we also call in with the next index position or the next column. We will
42:44:30
have to iterate over and we will keep on repeating the same process. Once we receive a call back from our board, we
42:44:37
will also have to explore other parts that we haven't explored so far. And that's where this recursive call comes
42:44:43
in. I remember first we are marking this current position as cube but next we are marking this current position as a dot
42:44:50
that this is no longer a cube and we are exploring other parts and this is the
42:44:55
whole solution. Now let's try to run this code.
42:45:03
Okay, seems like our solution is working as expected. Let's submit this code
42:45:10
and our code runs 87% faster than all the other solutions which is pretty good
42:45:16
comparing that how difficult question this one has been. Also in terms of memory usage our code is pretty good and
42:45:23
in terms of like much better than lot of the other solutions. Once again the solution of this code is present on our
42:45:30
GitHub repository. I highly urge you to go and check it out and try to solve this problem. If you can solve this
42:45:35
problem, I don't think any backtracking problem would be a cause of concern for you. Okay. Thank you.
42:45:56
So now we are going to solve maths for technical interviews. Now there is no point in giving introduction about
42:46:02
maths. We all live with it. We all have studied it in school. Uh and you can spend a lifetime learning math. So again
42:46:10
it's a huge topic but we are focusing only from the perspective of technical interviews. Now in the technical
42:46:16
interviews usually we deal with basic level maths. Nothing out of the blue. No
42:46:21
such kind of like integration or differentiation related questions and something very hard. It's always going
42:46:27
to be something basic. But you just need to have the mathematical temperament to understand that what is the core uh
42:46:34
ideology and concept underlying the existing problem. So we will see five
42:46:40
such examples of such kind of questions. And again this is basic mathematics uh nothing out of the blue. So you should
42:46:46
be able to understand it and I hope you find this section useful.
42:46:54
The lead code problem we are going to solve now is called + one. We can see that this one is a lead code easy
42:46:59
problem and also a very well-like problem. Basically, we are given a large integer that is being represented in an
42:47:06
array uh sense and represented as digits where every single value inside the
42:47:11
digit represents that particular position. So now we need to just simply
42:47:17
add one to this given array and uh returns a new value in the form of the
42:47:23
array. So without reading all of this let's just try to understand it normally. Let's say that we are given an
42:47:29
input. Basically uh originally we are supposed to be given value 9523 but this
42:47:35
is given in the form of an array. Now we need to do + one. So basically this value would become 9524
42:47:43
and this we need to return as the array. So we are going to once again going to create an array and we are going to
42:47:49
return 9524. And this is the answer that we will have to return. Same way if this these are
42:47:56
the digits we are given, we are simply going to return 1 0 02 but in the form of an array. Now the thing is when we
42:48:03
are dealing with any value that contains 9, then we will have to work about the
42:48:09
carry because we are adding one value to it. So if this is the value, we know adding one would yield the value is 1 0
42:48:15
0 0. So once again this is also going to be the array that we are going to have
42:48:20
to return. But now notice that because these were all four 9s this was a fourdigit character but this became
42:48:27
five-digit answer. So we will have to return an array with five entries and this is the only edge case where we'll
42:48:34
have to do something. Now logically if you are ever going to be presented with this question you are simply going to
42:48:40
use the most basic math of addition and subtraction. So you are going to take
42:48:45
whatever the value that we are given that let's say that we are given value 1 2 3 you are going to start traversing
42:48:51
from right to left and in this fashion first you will take the value if this
42:48:57
value is not 9 then we can simply just add one value to it and return the
42:49:02
answer. So in this case since this three is not nine so we can make it as four and then return the array as it is. So
42:49:09
we are only changing the one index value. Let's say that we are given a value something like 1 2 and 9. Now in
42:49:16
this case we know that this is a value 9. The moment we identify that there is a 9, we are going to change this to zero
42:49:24
and we are going to have to add one to this particular value and keep keep on repeating the same process. So basically
42:49:31
in this case we would have considered this to become zero. And now for this remaining portion 1 and two we can once
42:49:37
again repeat the same operation that we will have to add one value to it. So in this case for this one and two this is
42:49:44
going to be added with one more value. And since this is not nine so basically we are going to mark is it mark this
42:49:51
value as three and then return the answer as it is. Now the only problem is
42:49:56
if we identify for some reason that all the given characters are nine then in
42:50:02
this case what is going to happen? First we will try to add one over here. So then basically this would become zero
42:50:08
because this was 9. So we will have a value like this where currently this is
42:50:14
9. This is 9 and this is zero. But this 9 also has value one that we will have to carry over. Uh after the same
42:50:21
operation once again this would become zero. This would become zero and we would have one carryover above this 9.
42:50:26
Once again in the next iteration all of these three would have become zero. um sorry all of these three would have
42:50:33
become zero and we would still have one more carry that we are going to add in a
42:50:39
newly created value. So the simple algorithm that we can create is that we
42:50:44
will start iterating starting from right to left. If we identify that value does not contain 9, we simply do + one and
42:50:52
return the array as it is. For some reason, if we find that the value does contain nine, we are simply going to
42:50:58
mark that index position as zero and once again repeat the same operation for the remainder remainder of the array of
42:51:06
adding value one and keep on repeating the same process. For some reason, we end or we go through the entire array
42:51:12
and we identify that we are at the end of the loop. Then we simply need to create one more array that is going to
42:51:18
be the size one size greater than the previous digits array that we were given. And we are going to initialize
42:51:24
first value as one and all the other values as zero and return that as the answer. So this is the whole solution.
42:51:31
Now this is not any data structure or any problem that we are using. Uh so it
42:51:36
is going to run in of one constant time uh space time complexity sorry constant
42:51:42
space complexity. Now in terms of time complexity this is going to be dependent on the total number of digits that are
42:51:48
present. So this is still going to be big of n but it's not that much. It's a very simple problem and now let's
42:51:54
quickly see the coding solution for this one. So the coding solution is quite straightforward. All we need to do is
42:52:00
just iterate over all the digits from left to right. And we are going to have
42:52:05
a for loop uh to do exactly that. And then we are going to check that if the given digit is less than 9, we can
42:52:11
simply increment the digit and return the digits array as it is. If that is not the case, if it is nine, then we
42:52:17
will have to turn it to zero and repeat the same process for subsequent digits
42:52:22
moving from right to left fashion. Now in case if all the digits were nine that
42:52:28
we find out then we simply need to have a new array called new digits that is going to be one uh character longer or
42:52:37
one array space longer than the original digits array that we were given. And we are going to mark that value as one
42:52:44
because that is going to be the most significant bit and the all the other ones are going to be zero by default.
42:52:50
And uh then we can simply return the new digits array. So this is the whole solution. Let's try to run this code.
42:52:58
Okay, seems like our solution is working as expected. Let's submit this code.
42:53:04
And our code runs beautifully. Beats 100% of all these solutions. That is because it's a very simple problem. Uh
42:53:10
the coding solution is present in our GitHub repository. So feel free to go ahead and check it out from there. Thank
42:53:15
you.
42:53:30
So the lead code problem we are going to solve now is called happy number. Now we can see that this one is an easy problem
42:53:35
and also an extremely well-like problem. The statement is quite straightforward. We need to write an algorithm to
42:53:42
determine that if the given number n is a happy number or not and we are given the conditions that how can we define a
42:53:48
number to a happy. Now it is quite straightforward that starting with any positive integer n. We need to replace
42:53:56
the given number by the sum of the squares of its digits. So let's say that
42:54:02
we are given a digit like 16. Right? If n is equal to 16 in this case we need to
42:54:08
replace n with the square of its digits. So current digits are 1 and 6. So we
42:54:13
need to do 1 square + 6 squared. So this is going to become 37. And then once
42:54:18
again we will need to do the same thing for the 37 as well where we would do 3 squar + 7 squared. So this is going to
42:54:25
be 9 + 49. So I think it's 58. And yeah so so on and so forth. We would keep on
42:54:30
repeating this. Now we need to repeat this until either the number equals 1
42:54:36
where it would stay as it is or it would loop endlessly in a cycle which does not
42:54:42
include one. So either we need to keep on doing this process until this becomes
42:54:49
one or until we fi find out that there is actually a cycle that is happening and there are only two possibilities
42:54:55
either it could be a cycle or it could be one. Now for those numbers when which
42:55:00
process this ends in which ends in one are defined happy. So we need to return true for them and uh all the other ones
42:55:08
we need to return false. Okay. So let's try to understand how we are going to solve this problem by an example.
42:55:15
Suppose the given number n is equal to 19. So in this case the square is going to be 1 square + 9 square. So basically
42:55:23
81 + 1 so 82. Once again for 82 so it's going to be 64 + 4 so 68. Now for 68 so
42:55:32
total is going to be 100. Now for 100 it's going to be 1 square + 0 square + 0
42:55:39
square. So basically this is going to become uh the value is one. So because we find value to be one we can define 19
42:55:46
to be a happy number. And in this case we can return true. Now let's take one
42:55:51
more example. Suppose the given n is equal to two. This is going to be the full sequence and this is the full math
42:55:57
behind it. So you can notice that I have marked all the values defined as circles. And if you want you can just
42:56:03
pause the video at this moment and notice the numbers. But overall notice that we start at two and at some point
42:56:09
we end up at two as well. And if we keep going forward then next value would be four and so on and so forth. So we would
42:56:15
be in in an infinite loop. So in this case we can define the given number n is not a happy number. So we can return
42:56:21
this as false. So this is the ask of the problem. Now let's try to see the
42:56:27
solution. Now for this solution, brute force basically doesn't make that much
42:56:32
sense because it's very quite straightforward. We only need to take care of that whether n yields in value
42:56:39
one or if n yields in a cycle. Now we know whether if n yields in value one or
42:56:45
not. That is quite straightforward and easy to understand. We can keep on we can have a method that basically get the
42:56:51
square of the sum of given values and basically for the given value we keep on
42:56:59
repeating the process for given n where let's say the if the n value is going to be 55 first we do a modulo by 10 so we
42:57:07
get the last digit that is going to be five then we do it square and add it uh to the sum then once again we do the we
42:57:14
divide n by five so the remaining value is going to be 50 because this is going to be integer and then once again we do
42:57:21
it modulo by uh 10. So basically we would get value as five and then we will
42:57:26
just do the square of it. So this is going to be the full logic on how we will proceed with getting the square of
42:57:33
the sum. It's quite easy to implement and we would see that in the code. Now if we have to detect cycle all we need
42:57:39
to do is to keep track of all the n values that we have generated so far and
42:57:44
we will have to find a mechanism to quickly access that. So for every single new value of n that comes in we would
42:57:51
know that whether we have already visited this value or not and for that best way is to move forward by using a
42:57:57
hash set. So the idea is that we would have a hash set that would keep store of
42:58:02
all the different unique n values that we have found so far. And there can be two scenarios. Whenever
42:58:09
a new value of n is being found out either it could already be existed value
42:58:15
of n and which means we found a loop. So we we can check that using hashet in big of one time or the given value of n
42:58:22
could be one. If either of this cases happen then we simply get out of the loop and we return whatever the
42:58:28
subsequent value of n we found. So that's quite straightforward. Now if we see time and space complexity in this
42:58:35
case time complexity is going to be big of n because we are simply iterating over given input n once. Now space
42:58:41
complexity is also going to be big of n because we are using this additional hash to calculate all the possible
42:58:47
values of n. But overall this is a decent solution and a very easy problem.
42:58:52
So now let's quickly see the coding solution in this case. So the coding solution is actually quite
42:58:57
straightforward. First of all, we are going to initialize a variable called scene numbers. And this is going to be a
42:59:03
hash set that we are going to be using to keep track of all the numbers we have visited to make sure are we in a cycle
42:59:10
or not. Then we are simply going to have a while loop where we are checking that while the given n is not equal to 1 and
42:59:18
the current number is not present in the uh hash set of scene numbers that we
42:59:23
have seen. If that is the case, first of all, we are going to add the new unique entry to the scene numbers hashtag. And
42:59:30
then we are going to have a helper method called get sum of squares and pass in the value n. Now let's
42:59:37
understand this uh method. The helper method this is simply going to return an
42:59:43
integer value uh and we are checking that current sum is equal to zero. Now
42:59:49
while the given n is greater than zero, we are going to start breaking the given
42:59:55
value n based on digit by digit by doing a modulo of 10. And we are going to add
43:00:01
the square of that particular digit uh and add it to the existing sum. And then
43:00:07
we are going to divide the current n by value 10. And notice because n is integer so all the fractional values
43:00:15
would be eliminated and we are only dealing with raw integers. Now in the end we simply need to return the sum uh
43:00:22
once we are getting out of the loop and then based on this sum value we would
43:00:28
populate our n and keep on repeating the process. Now the moment we get out of the loop there can only be two
43:00:34
conditions either the given n is equal to 1 or we found a scenario where the
43:00:39
number was already present in the scene numbers. So in either case we need we simply need to determine that whether if
43:00:46
the n is equal to one we can return true if n is equal is not equal to one we can return false and this would be our
43:00:53
boolean response. So let's try to run our code.
43:00:59
Seems like the solution is working beautifully. Let's submit this code.
43:01:05
And our code beats lot of other solutions which is pretty good. Now we
43:01:10
could do some work in terms of space complexity. Now because we are using an additional hash set uh we are not the
43:01:17
best in terms of space complexity but there can be ways to improve upon them. Let me know in the comments if you want
43:01:23
to see the improved solutions and maybe I can put it in the GitHub repository. Meanwhile, this solution is present in
43:01:29
our GitHub repository. So, you can go ahead and check it out from there. Thank you.
43:01:46
So, the lead code problem we are going to solve now is called power of x to the power n. Now, this one is a lead code
43:01:51
medium problem and also a very well-like problem. But let's understand the problem statement. Basically we want to
43:01:57
implement a power of x to the power of n kind of a function. That's it. This is
43:02:02
the whole solution. So in the input we are given two values x and n where x
43:02:08
defines any integer. So let's say value is given two and n would define the power that we need to generate. So let's
43:02:14
say given n is equal to 4. So in this case we will have to return 2 to the^ 4. So this is basically going to mean that
43:02:21
2 * 2 * 2 * 2. So basically this is this turns out to be 16 and this is what we
43:02:27
need to return. Now for different kinds of input. It could be possible that the
43:02:32
given value of n could also be negative as well. So if the given value of is n is negative then simply uh let's say
43:02:40
that we are given the value 2 ^ minus 4. So in this case we can still perform the
43:02:45
same operation but basically we are just doing 1 / 2 ^ 4. So this is going to be 1 divided by 16 and I don't know what is
43:02:52
the decimal value but something like 0.06 or something like that. So this is what we need to return. Okay. So let's
43:02:59
try to see that what is the most simplest approach to solve this problem. We know that we are given a value of n.
43:03:06
It could be positive or negative. Let's consider those scenarios later. But let's say that value of n is given five
43:03:13
and we are given the value of x. So let's say x is given two. We can simply run a for loop uh that while n is
43:03:20
greater than zero basically we would keep on reducing the value of n 1 by 1
43:03:25
and multiplying the value of x by whatever the initial value of x we are given. So let's say currently x is equal
43:03:31
to two during the first iteration we are going to do 2 m* 2 and the value of n is going to be four then 3 then 2 then 1
43:03:38
and so on and so forth and in the end we can return this value as 32 as the answer. This solution would work as
43:03:45
expected. No issues with this. Now what is going to be the time complexity? The time complexity is going to be big of
43:03:52
the total number of n that is currently present and which is a fair enough time
43:03:57
complexity. It's not that complicated but the thing is uh we want to make
43:04:02
improvements to it and we want to make this faster and better solution that for any given value of x let's say the value
43:04:10
of x to the power n that we are trying to calculate we can also write this value in x²ared and then we do n / 2
43:04:19
because if we do ls with rhs then basically x would become x * 2 * n / 2.
43:04:28
So this is also going to be x ^ n. Right? But logically we can come up with this solution. Now notice that by
43:04:36
squaring the x with itself we are reducing the value of n by two and we
43:04:41
can keep on repeating this operation every single time. So in that case the
43:04:47
solution would run in of logarithmic of n time complexity. Now let me give you
43:04:52
an example on what I mean. Let's take our scenario where given x is equal to 2 and we're given n the value of n is
43:04:58
equal to 4. We know that 2 ^ 4 would become 16. But uh let's try to use my
43:05:05
formula. So in this case for 2 ^ 4 we can say that 2²ar and then we can also
43:05:11
do like on top of it here the value is four. So 4 divided by 2. So this is going to be two as well. 4 divided by
43:05:18
two. I hope you understood. Now if we do that we know 2 square is going to be four and this value is going to be two.
43:05:25
So basically this is going to be 16 and we can return this as the answer. Now notice in this case all we had to do is
43:05:31
just do this one iteration once. We did not have to do 2 * 2 * 2 * 2. So this is
43:05:38
a much better solution. But of course it comes with an additional cost on itself.
43:05:44
Now let's try to think that how we can take care of negative scenarios. So if
43:05:49
the given value of n is going to be negative value once again same method can apply but in this case if 2 to the
43:05:56
power of -4 then we need to do 1 / 2 ^ 4. So in this case we do 1 divided by 2
43:06:02
the 2 ^ 2 and then on top of it it's going to be two. So once again the same set of steps are going to be done. The
43:06:09
only thing is for negative value of n we would change the value of given x to 1 /
43:06:15
x. So I hope that also makes sense. Now there is another scenario that we did
43:06:21
not consider and that is that so far we consider this value of n to be uh an
43:06:27
even value. So that's why doing like uh this operation of uh n /ed by 2 was easy
43:06:35
like this operation. But what if this was an odd odd value? So if let's say for some reason we are given x ^ 5. So
43:06:43
in this case we can also treat this as x * x ^ 4. So in this case we would just
43:06:49
first multiply it with the current value of x and then we would have an even value of n and then we would just simply
43:06:56
return the same logic. So this is going to be x multiplied by uh x²
43:07:01
uh and square of it. So yeah that's the whole point. Now there is also one more
43:07:08
last final edge case and I know you all must be done with all the edge cases but if the given value of n is equal to0
43:07:15
then anything to the power 0 is always going to be one. So this is the standard thing. So we can just directly create a
43:07:21
case and return that that if the given n is equal to 0 we can directly return value as one. So let's do a quick recap.
43:07:28
we are basically going to do x to the power of n uh as x²ar and n / 2. If the
43:07:35
given value of n is odd then we are going to do x * x uh² and n / 2. If the
43:07:43
given value of n is negative then we are going to first convert x is equal to 1 / x. That's it. So this is the whole
43:07:50
solution. It works as expected. Time complexity as mentioned it's going to be because of log n which is exceptionally
43:07:57
good. space complexity apart from storing couple of variables we are not storing much so it's not going to be
43:08:03
that expensive and uh now let's see the coding solution so the coding solution
43:08:08
is going to be quite straightforward first we are going to handle the base case where if the given value is equal
43:08:14
to zero then anything to the power of zero is going to be one so we can quickly return that now if that is not
43:08:20
the case first thing we are going to do is to convert the given n that is an int value to the long value and this is
43:08:27
being run for some specific edge case scenarios nothing more than that. Then we are going to check that if the given
43:08:33
n is equal to negative we will first have to convert n to positive and we will also have to replace the value of x
43:08:39
with 1 / x. So basically we are going to be treating n as positive every single
43:08:45
time no matter what the value has been given but we will just update the value of the given x. Now we are going to
43:08:51
create a variable called double uh result and current product and this is to store the total results and the uh
43:09:00
appropriate result that we need to return. Okay. Now we are going to use our log logarithmic function where as
43:09:08
long as n is greater than zero we are going to check that what is going to be the modul of n by two if the value is
43:09:17
one which means the given n is an odd number. So we are just going to do result multiplied by current product
43:09:23
once. So that way basically we are going to be taking care of treating n is equal
43:09:29
to even numbers from for the subsequent values. Then we are going to be multiplying the current product with the
43:09:35
current product. So basically square the base and then divide the value of n by two. So at every single step we are
43:09:43
making the value of n turning it into half and then doing the multiplication. So and then in the end we can simply
43:09:50
return the result. So let's quickly try to run this code.
43:09:56
Okay, seems like our solution is working as expected. Let's submit this code
43:10:02
and our code beats 100% of all the other solutions. And that is because we are solving this problem in big go of uh
43:10:08
login time which is exceptional and we are also beating lot of other solution in terms of memory and that's because we
43:10:15
are just doing things efficiently. So once again the coding solution is present in our GitHub repository. Feel
43:10:21
free to go and check it out from there. Thank you.
43:10:35
The coding solution we are going to solve now is called multiply strings. And we can see that this one is a lead
43:10:41
code medium problem and also a very well-like problem. Now in this case we are given two integer uh nums one and
43:10:47
nums two but they are represented as a string and we need to return the product
43:10:53
of num one and num two which also needs to be represented as a string. Now in
43:10:58
this case we cannot use built-in library that converts string to integer and then
43:11:04
just do the multiplication on its own. So we'll have to find a clever way to do it and the logical way is very
43:11:11
straightforward. Basically we are just going to apply the same technique we learn sometime in the grade third or
43:11:17
fourth. Uh let's say that if I tell you that I have this number 24 and 7 and I
43:11:22
need to do multiplication of these two number. What is the going to be the simplest logic? So in this case 4 * 20
43:11:29
uh 27 is going to be 28. So I'm going to use 8 and the carry is going to be two.
43:11:34
Then once again 2 * 7 is going to be 14. 14 + 2 is going to be 16. So I'm going
43:11:39
to be storing this value and this is the multiplication result. Let's try to up the ante and let's try to do 12 * 13.
43:11:47
Right? In this case we are going to do the multiplication in two steps. And first step is going to be multiplying
43:11:54
this three with this 2 and 1. And then next step would be one multiplying this
43:12:00
one with this one and two and then storing the result. Now notice every single time we move one digit to the
43:12:06
left we are going to add a zero subsequent zero as well. So let's do that. So this is going to be six mult
43:12:12
and this is going to be uh three. Okay. Now we will have to multiply one with
43:12:18
this 12. But actually we are multiplying 10. So we are going to be adding one zero over here. And then this is going
43:12:25
to be two and this is going to be one. And we are going to do the sum of these two values. So this is going to be this
43:12:31
1 5 6 and this is the result. So basically this is the whole idea of how we can multiply multiple digits or like
43:12:40
two digits that contains multiple digits. Uh number one thing is we need to start from the rightmost position.
43:12:47
Now starting from the rightmost position we are going to take a digit uh like in
43:12:54
nums one or nums two let's say that num for nums two we took one digit that is going to be this three we are going to
43:13:00
take this digit and multiply with every single value of this nums one okay so we
43:13:07
can do that next thing is we are going to store this value somewhere that where
43:13:12
it needs to make appropriate sense and this appropriate sense comes from two
43:13:18
portions. First one is number one depending on the index position we can determine that where this value should
43:13:26
stay. Now let's come back to our computerbased solution. Number one thing
43:13:31
is if we are given two digits nums one and nums two we need to store them
43:13:36
somewhere and the logic we are going to apply is that we are going to store them be storing them in an array. Now the
43:13:43
maximum length of this array can only be the total length of the sums of digits
43:13:49
n1 and n_sub_2. So we can generate an array like that. And I don't want to get into mathematical explanation on why
43:13:55
that is the case but that is the case. Trust me on this. So let's say you generate an array that is going to be
43:14:02
storing the result. Now after doing that we'll have to do the tedious operation of storing the result for every single
43:14:08
value. But we don't need to do one by one. We'll need to figure out what is going to be the appropriate space where
43:14:14
we can directly store the results. So let's say that this is going to be 3 multiplied by two. So we know that we'll
43:14:19
have to store six somewhere in this array. But where the six is going to lie? That is going to be sum of the
43:14:25
index positions of these two values. So let's say the index position over here is 0 1 2 and 3. Now the index position
43:14:32
for this one is going to be 1 and the index position for this one is also going to be 1. So 1 + 1 is going to be
43:14:39
two. So we need to store this value in I index plus J index + one this value. So
43:14:46
we store it over here. And if there were to be a carry which is not in this case
43:14:51
or let's say instead of this being 12 what if this value was 16. So in this
43:14:56
case we would have stored eight over here and then there would have been a carry and that carry would have been
43:15:02
stored or one step before that. So this is where we would take take their carry
43:15:07
in and then once again repeat the same operation for this two values and find the appropriate index position to insert
43:15:14
that value like this. So the multiplication is going to be stored at
43:15:20
i + j + 1 location. I just explained why. And then carry is going to be
43:15:26
stored at i + j location because that is going to be one location lesser than the
43:15:32
previous location. Now the question is how we are going to convert all of this string into numbers. So we cannot use
43:15:40
directly parse int method but we can do it at the character level. So at a character level we can just subtract the
43:15:47
value from zero and then whatever subsequent values we can actually convert that into integer. So I'll show
43:15:53
you in the code on how it's done. So now let's see that what are the things we
43:15:58
have. Number one, we have the way to convert nums one and nums two into integers. So let's say we would have
43:16:05
values like this. Next thing is we are going to have a result array where we
43:16:10
are going to be storing all the results of all the calculated values. And last thing is we are going to apply the
43:16:16
common method of multiplying all the values or like digit by digit. So taking
43:16:21
in one digit and multiplying with all the other digits and once again repeating the same operation for all the
43:16:27
remaining ones taking care of the carry and storing them in the appropriate position inside the result array and
43:16:34
that we are going to be doing by doing I + J + 1 and I + J for the carry. Okay so
43:16:40
I hope this explanation makes sense. Multiplication it's quite straightforward. We are just going to do
43:16:46
it the same way we have been doing since second grade and that is to take care of all the values uh and then take care of
43:16:52
the carry and whatever the value is we can store it in the answer. This solution would work perfectly well uh
43:16:59
and in the end there is going to be one last thing that we need to do because we have the result being stored inside an
43:17:06
array. We will have to convert this array back to string and which we can do
43:17:11
it using string builder or there are many inbuilt methods that can do it and we are allowed to do it and lastly we
43:17:18
need to convert it into two string and return that as the answer. So this is the whole solution. This would run in
43:17:25
big of multiplied by n time complexity where m is the total number of digits present in nums one and n is the total
43:17:32
number of digits present in n2 because we are multiplying all the digits with all the other digits. There is no faster
43:17:38
way to do it apart from this and u it's acceptable because that is what the
43:17:44
question demands and uh in terms of space complexity because we are using an additional array to store all the values
43:17:50
this is going to be big of n + m where once again n is the total number of digits for n1 and m is the total number
43:17:57
of digits for n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n two nums two and this is an acceptable solution. Now personally
43:18:04
if someone asks this question in an interview I think I don't think like it's a very valid question to begin with
43:18:12
but it's a popular question and sometimes interviewer like to throw some
43:18:17
curve balls at you. So hopefully you can tackle them just as easily as I explain.
43:18:23
But overall now let's move on to the coding solution for this one. Now the coding solution is not the most
43:18:29
straightforward one. Even though the problem is very simple. So let's walk through the coding solution. First we
43:18:35
are going to check for an edge case that either num one or num two is equal to zero. We can simply return zero. If that
43:18:42
is not the case, we are going to initialize our result array that is going to be of the combined length of
43:18:49
num 1 plus num 2 and then we are going to iterate over every single i and j
43:18:56
combinations. So we are going to use two for loops to iterate over all the numbers. Now notice that we are going in
43:19:03
reverse. So we are going from rightmost position to the leftmost position. Now
43:19:09
for every single character we are going to multiply uh both like we are going to
43:19:15
multiply digit by digit and even though we cannot use directly parse int
43:19:20
mechanism we can still convert uh any particular string value to appropriate
43:19:26
integer value by doing this operation at the character level and then we are
43:19:31
going to multiply both of these two digits. After that important thing is to find appropriate position inside the
43:19:38
result array to store that product and we are also going to need to store the
43:19:44
high value that is where we are going to be calculating the carry. After that we
43:19:49
are we will add the multiplication result to the current position and also
43:19:54
handle if there exist any query uh or say any carry and then uh we are going
43:20:00
to set the current position to the remainder value of the result position low and also divide it by 10 to find the
43:20:07
high position value. Uh so we can work with appropriate next values that are going to be coming in. Then we'll need
43:20:14
to convert this array result array into a string which is quite straightforward. We are just going to use the string
43:20:20
builder function and then we can check that if the return the product value if
43:20:27
that is equal to zero we can simply return zero. If that is not the case we'll just convert it to the two string
43:20:32
and return whatever the value it is as it is. So let's try to run this code.
43:20:38
Okay, seems like it's working as expected. Let's submit this code.
43:20:45
And our code runs beautifully beats most of the other solutions which is very good also really good in terms of uh uh
43:20:52
space complexity as well. So once again the coding solution is present in our GitHub repository feel free to go and
43:20:58
check it out from there. Thank you.
43:21:13
Hello friends, hope you are having a fantastic day today. So now we are going to do an awesome lead code problem called detect squares. And we can see
43:21:20
that this one is a lead code medium problem and also not very well-like problem because it's like quite
43:21:26
complicated to understand. But I really found this problem quite fascinating. So let's try to work on this. Basically, we
43:21:33
are given a stream of points on an XY or two-dimensional plane and we need to
43:21:39
design an algorithm that basically does two things. First, it adds the new points that we are getting of stream of
43:21:46
XY plane data structure in like basically storing them somewhere in a
43:21:51
type of data structure and duplicated endpoints are allowed and they should be
43:21:56
treated as different endpoints. So we'll have to keep track of the frequency of any particular endpoint at any given
43:22:02
moment. Second thing is given the query point uh we might be needed to implement
43:22:09
a method called counts where we are given a point XY point where basically
43:22:15
we need to determine that out of all the points that we have added so far based on the given counts point are we able to
43:22:22
generate any squares and if we can we need to determine that that what are the
43:22:27
total number of squares we are able to make using that particular point and all the other previously uh points that we
43:22:35
have received. So basically we need to uh implement a detect square class and
43:22:41
we need to have two methods in it. First one is add that basically adds a point
43:22:46
and second one is count that returns that how many number of squares that we have we have been able to generate. Now
43:22:52
let's try to understand this with an example. Typically we would be given an input like this where first we are
43:22:58
initializing the detect square class and then uh we are adding bunch of the values and we are also at random
43:23:06
instances asking for a count of total number of squares that we have been able
43:23:11
to detect and these are the end points that we are adding. So now let's try to see how it looks like visually. So
43:23:18
basically in this example uh first we initialize this uh detect squares then
43:23:25
we add three values. So those three values are 1 1 3 and 3 1. So they are
43:23:31
over here 1 1 3 and 3 1 only these three values. Okay. And at the same time we
43:23:38
also come up with uh a count mechanism where we are trying to check that does there exist any square from this 31 end
43:23:46
point. So basically uh from this particular endpoint are we able to generate any squares. Now notice that at
43:23:52
this moment in this method we only have these three points. So we are not able to generate a square at the moment. So
43:23:58
we will return zero for that count method. But subsequently we add one more
43:24:04
point that is this 33 and which is defined over here. And after that once again we ask the same question of
43:24:10
generating a count and to which we can notice that now we are able to generate a square and a square is simple that
43:24:18
every single edge should have the same length and they should be per perpendicular to each other. So in this
43:24:24
case each of the this has a length two and they are perpendicular to each other like x and y axis. So that's why this is
43:24:30
a square that we can form using this 31 point. So in this case we would return one as the answer and we could have a
43:24:39
case where let's say uh next value we are trying to add is once again 3. So we would have one more point over here and
43:24:45
then we are being asked to check that are we able to generate detect any squares using this 31 endpoint. So now
43:24:51
in this case we can generate two squares. First square looks like this and second square looks like the other
43:24:57
previous endpoints. So basically in this case we would have returned to but you get the point that we what we are trying
43:25:02
to generate. Now understanding this problem is actually quite complicated.
43:25:08
How do logically we can make this solution work basically and then we would try to understand that how can we
43:25:14
tackle of implementing add method and how can we tackle implementing the count method in the most efficient manner. Now
43:25:22
let's try to visually understand the solution approach. uh we are given these
43:25:28
four points. We are trying to determine that how many squares we are able to generate using this 31 end point. Number
43:25:34
one thing that we are going to do is to check that do we have any other points
43:25:39
that are common with x endpoint values. So in this case we can find that there
43:25:44
exist a value 33 that is different from this point because we also have an
43:25:50
endpoint called 31 that is currently plotted. uh but we cannot use the same endpoint in this case. So let's say that
43:25:57
we want to find a value that has x but a different y. Okay. So we find a
43:26:03
corresponding value value 3 3. Now we know that these two are going to be in a straight line. Now if there were to
43:26:11
exist another value that can generate a square basically it has to be of the same edge
43:26:19
length as this one. So it has to have the value two as the edge length of it.
43:26:25
Okay. Now we have one of the edges for the square. What would it allow us to
43:26:32
generate the square? Number one thing is we can iterate over all the other remaining points and try to see that
43:26:39
what are the different points we have and are we able to generate a square from that or not. But in this case we would have to take a look at all the
43:26:45
different three remaining sides. That is going to be an expensive operation. Second approach we can do it is that
43:26:52
based on these two end points we can determine that what are the end points
43:26:57
we are going to need because we already have the distance two in order to generate a square. uh and we know for a
43:27:04
fact that if let's say that on an empty graph we only have the values 3 3 and 3
43:27:11
1 and we are being told that these are this is one of the side of your square
43:27:16
then other side of the square has to live uh somewhere over here or over here
43:27:23
where the distance has to be two in either case and let me explain what I
43:27:28
mean because we can only generate a square like this or we can generate a
43:27:34
square like this because this is a common edge. This has to live there for sure and we know that this this distance
43:27:41
has to be two and this distance also has to be two in order for a square to exist. So what are the potential end
43:27:48
points? We know that this is 3 1 and this is 3 3. So if there there has to be
43:27:54
a square with value two possible then that value is going to be so this value
43:27:59
would have become where we are adding the x coordinate to with value two. So basically this would have become five
43:28:06
and three and this would have become basically 5 and 1. If let's say we had
43:28:12
this end point present, we could have generated a square because notice that the difference would have been two on
43:28:18
each side and this has to be two because of this. Or second option is that we
43:28:24
could have on the other side. So that is going to be x minus 2 values for both of
43:28:29
them because y-coordinate is going to remain constant because we are aligning our match based on the y-coordinate. So
43:28:37
this value would become basically 1 and uh uh 3 and this value would become 1
43:28:44
and 1. And we know that now we already had one side that was 3 3 and another
43:28:52
side that was 3 1 potential two values we found is either 53 and 51 or 1 3 and
43:29:01
1 uh 1. So now the thing that we need to do is is to check that amongst the added
43:29:09
endpoints do we have either these two entries or these two entries. It's not
43:29:14
like if we have 1 3 and 53 it would work. No it would not work. It has to be pair of 1 3 and 1 or pair of 53 and 51.
43:29:23
And in this case we know from the input that we have a pair 1 3 and 1. And if we
43:29:29
are able to find these end points basically we are able to generate a square. So we can just update that value. And it could be possible that if
43:29:37
we had this point let's say 1 3 two times and 1 one two times then in this
43:29:43
case we would have generated 2 * 2. So in total four squares. If we only had
43:29:49
this like two times uh and uh this value maybe just once. So in this case we
43:29:55
would have generated two multiplied by 1 because of the number of occurrences only two squares. So we will have to
43:30:02
keep track of the frequency of endpoint as well in order to determine that what is going to be the fastest solution. So
43:30:09
now let's come back to our original ask. We basically were given a data structure
43:30:16
where uh sequentially we are adding the values. Now in order to add the values
43:30:22
what are the things that we need to take care or we need to understand number one we need a quick way to look up whether
43:30:28
any particular x value ex x x coordinate exist or not and why are we considering
43:30:34
same can be said for the y-coordinate I'm just taking x because it logically makes sense why because remember in this
43:30:40
case we were able to quickly identify this end point and then we wanted to check corresponding values so
43:30:47
corresponding values would have been like 53 and 51 or 1 1 and 1 3. So in
43:30:54
this case we were able to checking based on the x end points. That is number one thing. Second thing is we also need to
43:31:01
store appropriate ycoordinate in accordance with the x coordinate because
43:31:07
there are pairs being present for x y pair. And third thing is uh we need to
43:31:12
know the frequency of any particular endpoint. So if let's say this 13 was
43:31:18
present two times I wanted to know this quickly. So what is what uh data
43:31:24
structure comes to your mind in order to store this information that can fulfill all of this. Number one if we are trying
43:31:31
to store x and y we could have used something like hashmap. But in this case apart from storing x and y we also need
43:31:37
to store the frequency as well. We can still use hashmap but this this is going to be like a slightly complicated
43:31:43
hashmap because number one we are going to have a hashmap where we need to have
43:31:49
key value pairs. So we are going to key and value combinations as key we would
43:31:55
treat the xcoordinate values. So let's say that currently first we had the value 1 one we would have added one over
43:32:02
here and as its appropriate value we are also going to store one more hashmap a
43:32:08
mini hashmap within hashmap and that two is going to work uh run basically the
43:32:14
same way it is going to have a key wault pair of its own where the key is going to be the y-coordinate so basically this
43:32:21
is going to be value one and the value is going to be the frequency of ycoordin
43:32:27
ordinates occurrence because we already have the frequency of x coordinates occurrence. We only need to keep track
43:32:32
that how many times the same ycoordinate occur for the same x coordinate. So in
43:32:37
this case the frequency is also going to be 1 one. So we can store that information. Same way next coordinate we
43:32:44
are adding is going to be 1 13. So once again the key one is going to remain common but as part of its value we are
43:32:51
going to have one more entry inside this hashmap where now the value of x co
43:32:57
ycoordinate is going to be three and its frequency is going to be 1. Okay then we
43:33:04
are going to have one more entry where the x coordinate is going to be 3 1. So we are going to have one more entry
43:33:10
three and as ycoordinate the value is going to be one and its frequency is going to be one. Same way we have one
43:33:17
more value 3 three in this case. So three we already have it as a key as an input. So we would have stored over here
43:33:24
the another value three that is the y-coordinate and its frequency as one. So we are keeping track of frequency at
43:33:31
every given instance and for every single xcoordinate we have the
43:33:37
subsequent y-coordinates and its frequencies. So it follows both of our
43:33:42
uh desired needs. Now we know how to quickly add a value. If we see time
43:33:49
complexity in this case this would have run in nearly big of one time every time because based on the x coordinate we
43:33:55
would be able to quickly look up uh and we would be able to see that what are the corresponding y-coordinates in also
43:34:01
big go of one time because we are using a hashmap in terms of time like space complexity this would become an big of n
43:34:08
solution for every combination of x and y pairs we would need to add new entries to the hashmap so we can generically
43:34:15
just mention that this is going to be big of n Okay, this would be our solution for adding um method or to
43:34:23
build this data structure. Okay, next portion of the problem is that how do we
43:34:28
detect squares? Now notice that for the detect square method basically we need
43:34:34
to generate that what is going to be the count of squares and we are given an entry point. So an xy coordinate that we
43:34:41
are already given. We can treat this xycoordinate as one of our x1 and y1
43:34:47
that we are trying to working with. So we are going to be dealing with an x1 value. And we can quickly check in our
43:34:55
hashmap that whether we have any other values for this x1 that is currently
43:35:00
present within our detect square method. So let's say that we wanted to detect
43:35:06
that for this value 31 how many number of uh squares exist. Okay. So in this
43:35:12
case for this 31 we know that the x value is three. So we will come to our hashmap and we will see that for this
43:35:18
three how many corresponding xy values we have. One value we have is going to
43:35:24
be three and one. And so this is one value that we currently are present. But
43:35:29
because it's the same x and y we cannot use this endpoint. So we'll just ignore this. Next value we have is 33. So next
43:35:37
value that is currently present is going to be 33. And that is pretty good that we can actually use this. So now we have
43:35:43
one endpoint is 31. Another end point is 3 3. So difference between y1 and y2 is
43:35:49
going to be two. Now because we have this value two all we need to do is to
43:35:54
add two to the one side of x and add two to the other side of x. So basically we
43:36:01
already have this one and one edge 3 1 and 3. So now we will need to determine
43:36:07
that + 2 on the x side. So that is going to be 5 1 and 53. Do we have this pair
43:36:16
present? And second one is 1 1 and 1 3.
43:36:21
Do we have like this combination present? And if either of this combination is present which again we
43:36:27
can quickly look up because we have we are storing all the information in a hashmap. So we can quickly look up
43:36:33
whether five is present as a as an input or whether one is present as an x coordinate and if they are present what
43:36:39
are the corresponding y values we can also take a look at the frequencies and then we would basically just detect the
43:36:45
squares and build the solution. So this is the whole solution and if we try to
43:36:51
understand the time complexity for basically count operation. This is
43:36:56
slightly tricky but not that tricky because we know that we can quickly look
43:37:03
up the values of x coordinate for any particular entry in big go one time. But
43:37:08
for that x coordinate there can be multiple ycoordinates. So in the worst case scenario, we might
43:37:14
have to iterate over all the possible y-coordinates as well because imagine let's say that instead of this being one
43:37:20
one if we have all of these bunch of different end points and even over here we have all of these bunch of different
43:37:26
end points for every single pair we have to keep looking for the combinations of different x and y coordinates. So that
43:37:32
would become an a hassle. So the time complexity for this count method would be bigo of m where m is the total number
43:37:39
of ycoordinates present because in the worst case we might have to iterate over all of them. So that's still relatively
43:37:46
a good time and space complexity given how complex this question could have been. So we are trying to use the logic
43:37:55
and power of math and some geometry uh to solve this problem and to not go
43:38:01
through the brute force route. So I hope the solution made sense to you. Now let's quickly see the coding approach
43:38:06
for this one. So the coding solution is going to be slightly complicated but
43:38:12
let's understand. So first we are initializing a private hashmap that is that we are naming as points count that
43:38:19
we are going to be using to adding all the values and notice that we have key as an integer and it subsequent value as
43:38:26
another hashmap. So there is a hashmap within an hashmap. Okay. Then we are going to have a detect square method
43:38:32
that is simply going to initialize the hashmap. And then we are going to implement the add method. Now in the add
43:38:39
method it's quite straightforward that we are considering the value x as 0 and
43:38:45
value y as 0.1. For every single x coordinate we are initializing a new
43:38:51
hashmap if the x coordinate is not already present. And then for every single y-coordinate we are checking that
43:38:58
if it is not present we basically uh add the frequency as one or if it is present
43:39:05
we basically update the existing frequency. So if it is present like two times we just add it to three. Okay. Now
43:39:13
here comes the meat of our problem that is the count method. Now in the count method as an input we are given an
43:39:20
endpoint. So we are treating its x and y coordinates as x1 and y1. This would allow us to iterate over all the
43:39:26
possible combinations and we are initializing a variable called total squares that we have found so far as
43:39:31
zero. Now the very first thing that we need to check is that does our hashmap
43:39:37
contains any other value that is on the same x coordinates as the given point x1
43:39:43
coordinate. If we don't have any values we can directly return zero. That's it. But if we do have bunch of points on the
43:39:50
xcoordinate then for each one of them we'll have to do the following and that
43:39:56
is that we would find that what are the subsequent y values. We will also try to
43:40:02
see that what has been the frequency of that xy combination. We would check that
43:40:07
if the y2 is equal to y1 which means we are at the same point that we are
43:40:12
already given. We can ignore that. If that is not the case, we would find that what is going to be the edge length or
43:40:18
side length by doing the subtraction of y2us y1 and this is going to be an
43:40:23
absolute value. So doesn't matter if it's like above x or below x overall we
43:40:28
are only dealing dealing with positive integer. Then we will have to check that
43:40:34
what are the possible values that would allow us to generate basically a square
43:40:41
and then we would add it to the existing list of total squares and for that we are using a helper method called count
43:40:47
squares where we are taking in x1 and y1 coordinates. We are also taking in x3
43:40:52
and y3 coordinates that we are trying to build and we have the y2 and the count
43:40:59
y2 so frequency of that coordinate. So after having all of this value in the helper method we simply check that do we
43:41:06
have the x3 coordinate that we were talking about and it subsequent y1 value. If we do what has been the count
43:41:13
frequency and we simply multiply that to basically add the value to our uh total
43:41:20
squares and we do it for both like x1 + side length and x1 minus side length. So
43:41:26
this would give us both set of end points and in the end we simply return total squares. Now I know the coding
43:41:32
solution looks quite long but if you just go and check it out our GitHub repository you would find that this is
43:41:38
uh an easier solution to understand once you know that what conceptual uh
43:41:44
solution means. Let's try to run this code.
43:41:50
Okay, seems like our solution is working beautifully. Let's submit this code
43:41:56
and our code beats 95% of all the other solutions which is exceptional and we
43:42:02
beat 91% of all the other solutions in terms of time complexity uh sorry space complexity as well which is also quite
43:42:08
nice. So this is present in our GitHub repository and I know that this solution
43:42:14
says it's a medium solution but in my opinion this can be treated as a hard problem as well because it's not quite
43:42:20
straightforward to understand.
43:42:35
The next topic in the sequence is going to be matrix where we are going to do the full course on different matrix
43:42:41
problems. Now matrix is nothing but an extension of array. It's a two-dimensional array that can be used
43:42:48
to represent anything. this video that you are seeing an image or a grid or a
43:42:54
graph or all sorts of different things. So we will solve some popular DSA problems and again introduction you all
43:43:01
have seen in the topics like array, two-dimensional dynamic programming, some advanced graph problems and all
43:43:07
sorts of places. We can use matrix to represent basically graphs as well. So you must have seen some examples of that
43:43:13
and this is just to solidify your knowledge. if you are specifically being asked on multi-dimensional array related
43:43:20
problems. So without any delay let's get started. Hello friends, we are not employed by a fang company. So let's not
43:43:25
solve lead coding till we get there. Today we are going to do set matrix zeros problem and this problem has been
43:43:31
asked by some of my dream companies. So companies are like Microsoft, Amazon, Facebook, Apple, Bloomberg, Adobe and
43:43:38
also sometime in the past there are there have been Google and Goldman Sachs and eBay they all have asked this
43:43:43
problem and that's why I'm paying my utmost attention. I hope you also enjoy the video.
43:43:49
So this is a lead code medium problem and it is a very well-liked problem. uh basically we are given an m byn integer
43:43:56
matrix and we are told that at any point if we identify that there exist an element that is zero then we need to set
43:44:03
that entire row and entire column as zero and uh we are also told that we
43:44:08
need to do it in place. So let's see it with an example. So over here in the
43:44:13
example we are given a matrix like this in the input and we can see that this is the element that is zero. So because
43:44:19
this element is zero, we will have to convert this whole row and this whole column to and set it up to zeros and we
43:44:25
need to return an answer like this one. Uh same goes with the second example that we are given a matrix like this
43:44:32
where we are to we are given two zeros at these two locations and because there are two zeros we will convert this
43:44:39
entire row and this entire column to zero because of this particular zero and
43:44:44
we will convert this entire row and again this entire column to zero because
43:44:49
of this particular node. So this row is common. So anyways we will just convert it to zeros and this would be the final
43:44:56
answer we need to return. So suppose this is the example that we
43:45:01
are given and let's see that what could be the most basic intuitive approach that comes to our mind. Well first thing
43:45:07
that comes to our mind is that we can actually start iterating over whatever this given input is and the moment we
43:45:12
encounter a value zero we can just convert that column and that row where the zero belongs to all and set it up
43:45:18
all to all the zeros. uh and let me show you that why it won't work. So first of all we'll start iterating over here. We
43:45:25
are we cross this node, this node and this node. We don't find any zeros. So we are good so far. Now at this point we
43:45:31
identify that there exist a zero over here. Which means that for this particular column and this particular
43:45:36
row we will have to convert it to zero. So let's just do that. So if if I if we do that what we will basically do is uh
43:45:44
we will remove all of these entries and now we will convert these entries to
43:45:49
zeros which means that uh this is zero this is zero and this will all be become
43:45:55
zero. Now the problem will happen that after iterating this element the moment we reach to this particular node we will
43:46:02
again have to convert all of these values to zeros as well. But remember that that should not have been done by
43:46:08
because originally the value over here was actually one which means that this
43:46:13
particular uh row this particular column does not needed to be create converted
43:46:18
to zero because of this particular node. So that is the problem over here. Let's see that what could be the solution. So
43:46:24
let me quickly draw back uh this to its original form.
43:46:30
One thing we can do is we can actually create a copy of this one. And in that particular copy uh we can actually uh
43:46:37
start making the change whenever we find a zero in this particular matrix so that
43:46:43
we do not end up changing the elements before they are being visited. So let me
43:46:48
quickly create a copy of this particular node. Okay. So now we have created a copy. Again we will start iterating over
43:46:54
all these elements. We won't do anything over here. We identify that that this is a zero element. The moment we identify
43:47:00
that this is a zero element, we will actually make changes to this particular copied element. So now we will update
43:47:05
the elements in this particular fashion. So all of these would be converted to
43:47:10
zero. Now again we start iterating over this one. So this is one. This is one. So we are good. This is also one. So we
43:47:16
are good. Now this is again a zero. So because this is a zero, we will again update this row and this uh this column
43:47:24
and this row in the copied node. So let me quickly make those updates
43:47:34
and this will be the solution. So in the end we can actually return this copied solution where there is only one entry
43:47:42
over here and all the other elements are zero. So this solution would work but the issue is that we are actually using
43:47:48
bigo of m cross n space over here. So let's try to see that can we do some
43:47:55
improvement rather than using this additional space.
43:48:02
Okay. So in the previous approach we used a new matrix to keep track of all the elements where the rows and columns
43:48:09
the entire things need needed to be turned out to zero. But this is actually not necessary. Uh remember that at any
43:48:16
point we identify that inside the given matrix if there exist a zero. All we need to do is we need to convert that
43:48:21
entire column and row set it and set it up to zeros which will happen in both of these cases. So because at any point we
43:48:28
identify a zero the change apply to entire matrix for that particular row and column. Why do we use the entire
43:48:36
additional matrix to store all the values? This is useless and better approach is that we can actually create
43:48:42
another uh set where we take care of all the row positions and all the column
43:48:49
positions and all we need to care is that at any point if we identify a zero
43:48:54
at any moment uh we simply need to enter that entry in those particular row and
43:48:59
column positions and then convert those row and column position to zero. So let me show you quickly show you how we are
43:49:05
going to do this. So over here we will start iterating all the nodes and we identify that uh these particular nodes
43:49:12
uh 1 2 and three these nodes they are not zero. So we are okay with this one but this is a zero. So because we
43:49:18
identify that there exists a zero node we will quickly note this position to this row and column entries. So we will
43:49:25
add an entry over here called zero and we will also add an entry over here called zero. Right? We are good so far.
43:49:32
Now again we will keep iterating over this given input uh in the similar fashion. So these two are also not zero
43:49:38
and this is also not zero. So we are good so far. Uh next we are going to do is that because this entry is zero again
43:49:44
we will record those positions inside this additional row and column set that we have created. And now uh this last
43:49:51
entry is also not zero which means we we don't care about anything. And at the end all we need to do is we need to
43:49:57
iterate over this additional created uh sets and see that at whatever position
43:50:03
we encounter the zero value for that particular row we will convert convert it to zero and that particular column we
43:50:09
will convert it to zero. So first of all we will visit this uh hash set of rows
43:50:16
and we identify that okay first one is zero. So because first one is zero all of these entries needed to be converted
43:50:22
to zero. So we will convert these entries to zero. So we are good so far. Again we identify that second is also
43:50:28
zero. So again we will repeat the same thing and we will get rid of all of these ones and we will convert them to
43:50:34
zeros as well. Now this last one is not one. So we are good and we will we will not touch this particular column. Now we
43:50:41
will do the same thing for this one. So this is because this is zero. We will convert all of them to zero. So this
43:50:48
becomes zero. And uh this one is also zero. So we will convert all of them. and this last cell also becomes zero.
43:50:56
And uh in the end we can just simply return this newly created matrix. So
43:51:01
this is a much bigger improvement than that in the previous one we were actually storing an additional uh entire
43:51:08
matrix where the space complexity is big of m cross n. So over here the space complexity is actually improved and we
43:51:15
are only using big of m + n. Why plus n? Because uh suppose the number of rows
43:51:21
are m and number of columns are n. So we are still creating this two additional hash sets with those particular element
43:51:28
values. Uh the question is can we actually do something better and even
43:51:33
not using this m plus n space and can we actually use the space complexity to be big of one and yes there is a solution
43:51:40
that achieves this in big of one as well. So let me quickly show you how.
43:51:48
Okay. So pre so previously we were actually using an additional data structure like this one to keep track of
43:51:54
all the rows where we need to change the value to zeros. So over here suppose we
43:52:00
identify that there exist there exist a zero over here we would update that value in this particular place and later
43:52:06
we would know that hey we need to convert all these values to zeros. And we are also using another data structure
43:52:12
to keep track of number of columns that needs to be converted to zero. In the same manner that over here we identify
43:52:18
that this is a zero. We will update an entry over here and we will mark this point as zero and later we would update
43:52:24
all of these nodes to zeros. But rather than using the separate nodes, what we can do is we can get rid of them. And we
43:52:32
can do the same thing by using this first row as an alternative for this
43:52:38
original uh additional data structure. And also we can use this first column as
43:52:45
an alternative for that original uh column data structure. And uh basically
43:52:51
we will do the same concept but we won't be using any extra space anywhere and
43:52:57
this is a wonderful approach. Now there will be one problem with this one and the problem would be that over here we
43:53:04
would be using this particular uh row to keep track of all the columns where the
43:53:09
value needs to be converted to zero and same way we will have to use this particular column to keep track of all
43:53:14
the nodes where the rows needs to be updated. The problem is that this particular position is actually a point
43:53:22
of conflict uh where there exist two intersecting nodes. So we will what we
43:53:27
will do is as a solution we would actually create an additional node and we will use these two nodes. Uh so these
43:53:36
three nodes would be working in combination and for the first column we
43:53:42
all we will need to do is just use this entire uh first row to keep track of all
43:53:48
the columns that needs to be updated and let me show you that how we are going to do the things. Okay. So first of all we
43:53:56
will iterate over this matrix and we identify that okay this value is one so we don't care this value is also one so we don't care. Now this value is zero.
43:54:02
So because this value is zero, we will have to make change to this particular uh row and this particular column. But
43:54:08
this is at correct position this zero for this row. So we only have to update it over here. So we will add an entry
43:54:14
zero over here. Right? Now uh next thing we will do is we will keep iterating over this matrix. So we'll update update
43:54:22
we'll check these three values and all of them are one. So we are good. This is also one. So we are good. Now this value is zero. So because this value is zero
43:54:28
we will have to update over here and also over here. So we will do that. So we'll convert this value and convert it
43:54:34
to zero. We will also convert this value and change it to zero. And uh at the end we will just iterate over this element.
43:54:40
And this element is already one. So we don't have to do anything. Now this is the matrix we have. All we will have to
43:54:46
do is we'll have to iterate over this and the these six nodes and at any position we identify the zero we will
43:54:53
convert that row or that column and change it to zeros. So first of all we will start iterating over this uh first
43:55:01
row and this is one so we are good but this is zero. So because this is zero we will have to convert all of these to
43:55:06
zero. So let's do that. So this value would be turned to zero and uh we are good. Now again we come at this position
43:55:14
this is also zero. So all of these values needs to be converted to zero. So we will flip all of those values to
43:55:19
zeros as well. Okay. Now we are done iterating over this first row. Now we will iterate over this first column. So
43:55:26
for the first column we identify that okay this particular position is zero. So because this is zero we will update
43:55:31
the entire this entire row as zeros. So let's do that. So we will get rid of this first value and we will change it
43:55:38
to zero. Now we will iterate to this next node. So this is one. So because this is one we will not touch this row.
43:55:45
So we don't have to do anything. And because this is zero. So this because this is zero we will have to convert
43:55:51
this entire row to zeros. But since these two nodes have already been converted to zero, we don't have to do anything. And this would be our final
43:55:57
solution. So uh if we write the answer, we can actually write an answer like
43:56:03
this one. This would be our final answer. And we can actually return this as the answer.
43:56:09
And this solution works perfectly fine. Let's see the time and space complexity in this case. So the time complexity is
43:56:15
actually going to be big go of m cross n. Why? because we will have to iterate over this entire matrix and uh that
43:56:22
takes m cross n time. Uh in terms of space complexity we already know that we are only using this additional node. Uh
43:56:29
apart from that we are not using any additional space. So the space complexity is actually constant space
43:56:34
and this is the final solution. This solution is very good. And let's see the coding.
43:56:43
First of all, we will create an additional variable and we'll create a boolean variable and we will just name
43:56:48
it as first column. We'll initialize the value as false. And now we'll have to
43:56:53
iterate over the matrix. So we'll need to know the length and height of the matrix. So let's initialize two
43:56:59
variables uh to store the height of row and column of the matrix.
43:57:05
Now we'll have we'll start iterating over the matrix and we'll start updating the value inside the first row and first
43:57:11
column. So we will check that if inside the given matrix for the first row if there
43:57:17
is any element the where the value is uh actually zero then we will convert that
43:57:24
uh and we will update the value of the first uh call variable.
43:57:30
Once that is done we will also have to iterate over all the columns. So we will create another loop inside the loop.
43:57:41
And now we simply have to check that whether at any position we end we are encountering any value that is zero. If
43:57:49
there is any value that is uh zero we will have to update the corresponding I
43:57:54
and J position inside the first row and column subsequently.
43:58:00
So once this loop ends uh all the values should have been stored uh inside the first row and first column. So all we
43:58:06
will have to do is iterate over the first row and first column and we will update the subsequent rows and columns.
43:58:16
So we will check that if at any position uh the corresponding value for the i and
43:58:22
j position if that is zero inside the first row we will have to update the element of the m this particular node
43:58:28
inside the matrix to zero as well.
43:58:33
And once this loop ends, we would have taken care of all the elements inside the given matrix. But we notice that we
43:58:40
are running this loop from i equal to 1 and j equal to 1. Which means that we are not taking care of first row and first column. So we will have to take
43:58:46
care of first row and first column. Now remember in order for us to take care of the first row, we will have to check the
43:58:52
first very first element which is this uh this particular element inside the given uh matrix. So we will do that. So
43:59:01
we will check that if a matrix at 0 0 position if that is zero we will
43:59:10
have to update all the values inside the first row
43:59:18
and once that is done we will also have to check for the first column. So for that we will we actually have a variable
43:59:25
first column and if the first column variable if that is true then we will have to update the first uh column to
43:59:32
zero and uh after this ends I think we should
43:59:39
have taken care of all the nodes. So let's try to run this code.
43:59:45
Okay. Uh seems like a compilation error.
43:59:51
Okay, seems like our solution is working. Let's try to submit this code.
43:59:57
Our submission did not work for this one.
44:00:03
Oh, we'll have to start from J equal to 1 inside this first column. So, let's
44:00:10
try to run the code again. Let's try to submit it again. Okay, seems like our
44:00:15
solution is working and it's actually pretty efficient compared to a lot of other solutions. I would be posting this
44:00:20
inside the comments so you can check it out from there. Also, I have created a repository inside the GitHub where I
44:00:27
have posted the solution of all the Java problems that we have done so far inside the lead code. Okay. So, this is the
44:00:33
repository. You can go to any problem and you would be able to find the accepted Java solution for that
44:00:40
particular problem and I would be posting this link inside the description as well. So, you can check it out.
44:00:56
Hello friends, we are not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do spiral matrix lead code
44:01:02
problem. And this problem has been asked by tons of my favorite companies. uh companies like Microsoft, Amazon, Apple,
44:01:08
Facebook, Google, Adobe, Uber, Bloomberg, Tik Tok, Walmart, Tesla, PTM,
44:01:16
Flipkart, Bite Dance, eBay, Goldman Sachs, Robin Hood, and Salesforce. So,
44:01:21
you can imagine that this problem has been really popular at top tier ID companies and that's why I'm paying my
44:01:27
utmost attention. I hope you also enjoy the video. So this is a lead code medium problem
44:01:32
and basically we are given an M crossN matrix and we need to return all the elements inside the matrix in a spiral
44:01:39
order. So suppose we are given matrix like this in a 3x3 matrix. We need to iterate over this given matrix in this
44:01:45
following fashion in a spiral and return elements in that sequence. So to make things more understandable I have drawn
44:01:52
different matrix of different sizes. And let's see that what would be the spiral traversal for each one of them. So we
44:01:57
will always start at the 0 0 position and then we will start traversing on the right side until we hit a boundary. So
44:02:03
over here we hit a boundary and then because we hit a boundary we'll go downwards. Now again downwards we hit a
44:02:09
boundary again. Again we will go in the left direction. Again we hit a boundary over here of the matrix. Now we will
44:02:14
again go upwards in the direction. But now this time we will not wait for us to uh hit a boundary. We will actually stop
44:02:21
at this position number four. Why? Because if we keep going uh in this upwards direction we will end up at this
44:02:26
position number one which is though it is before the boundary still this is the node that has already been visited which
44:02:33
means that we are traversing in a particular direction until the point where whether we hit a boundary or we
44:02:39
hit a visited node. So this is a really important concept to understand. Now let's go back to the traversal. So again
44:02:45
from this four we will come back at this point five. And now from this five you can realize that there is no other
44:02:50
direction this file can go to and this would be the answer. So this would be the end of the traversal. Let's see
44:02:56
let's do the traversal for this 4x4 matrix. So again we start at this initial position. We start going on the
44:03:01
right direction. Then again we go downwards again we go leftwards. Then we go up until the point when we hit uh
44:03:08
this visited node. Again we go right. Again we go down and again we go left. And this would be the traversal for this
44:03:14
5x5. Let me quickly show you what would be the traversal. And of course it's pretty simple to understand. So I know
44:03:19
you also know that what would be the traversal. This is how we are traversing in each
44:03:25
one of each all three of the cases. Now remember that there are two important things to consider over here. First
44:03:32
thing is that at any point we are traversing we are always following a pattern in terms of the number of
44:03:38
directions or the type of direction we are taking. And that pattern is always we start at the initial position uh
44:03:45
which is this one. And then we always go on the right side first. After going the right direction, we go downwards. So we
44:03:52
go downwards. After going downwards, we go leftwards. And after going leftwards, again we go in the up direction. So we
44:03:59
go upwards. Then again we go back on the rightwards. Again we go down and again we go left and right up. And we keep on
44:04:06
following until we reach to a point where all the nodes that are adjacent to any particular node. So in this case
44:04:13
this number 10 where all the other nodes they have already been visited. In this case it would be this node number 13
44:04:18
where all the other nodes they have already been visited. So we are traversing until the point where we
44:04:23
exhaust out of all the nodes that we can traverse. And let's see that what would
44:04:29
be the approach for us to solve this problem. Like we already know that what are the directions we need to traverse
44:04:35
into and we are always traversing in a in any particular direction until the point where either we hit a boundary or
44:04:41
we hit a visited node which means that these things are important for us to keep track of that this boundary or this
44:04:49
visited node. We need to understand that how to identify them, how to keep track
44:04:54
of them and what are the different approaches to tackle both of these and what would be the solution. So in order
44:05:00
to solve this problem there are actually two different solutions. I'm showing you both of them. You can pick whatever you
44:05:06
want to. Both have its pros and cons and you can discuss it with your interviewer which solution you want to pick. So
44:05:11
let's go with the first one. Now first approach is that we actually
44:05:17
start shrinking the boundaries and we don't care about visited nodes. How we are going to do it? Let me quickly show
44:05:22
it to you. So first of all we always start at this initial position. We know the directions we need to take. we go
44:05:28
right then we go down then we go left and then again we go up. This is the the state of direction we are going to
44:05:34
follow. Let me also create our answer of the nodes that we are going to uh traverse along. So first of all we start
44:05:41
at this position number one and then we follow up until this point where we hit a boundary over here. Now the moment we
44:05:48
hit a boundary over here we are going to add all of these values to our answer. So let me quickly add all the nodes to
44:05:54
my answer. And then because we hit a boundary over here and this was the direction right direction. We know that
44:06:00
next direction we need to go is downwards. So we start going downwards. But we are going to do one thing
44:06:05
important over here. And that thing we are going to do is we are going to ignore all of them and we are going to actually shrink our boundary up until
44:06:12
this point. So originally this matrix was actually 4x4 matrix. Now we are going to convert this matrix to be a 3x4
44:06:20
matrix and we are going to ignore this first row as if that never actually
44:06:25
bothered and that never actually existed. Uh so by doing so what we are doing is that we don't need to take care
44:06:32
of these uh elements and since we have already added them to our answer so they are always going to be in in our answer
44:06:39
as well. Right now again we go downwards in the same path until the point where
44:06:44
we hit a boundary. So we hit a boundary over here. We are going to add all the nodes to our answer. So nodes would be
44:06:50
8, 12 and 16 in this sequence. And again we are going to ignore all of them
44:06:56
because we have seen all of them. And now again we are going to shrink our boundary up until this point. And we are
44:07:02
going to ignore all of these places. So let me actually remove them that they never existed for us. Now again after
44:07:10
downwards we will start traversing on the left direction. So we go until this point. We will add all the entries on in
44:07:16
our answer. And again we are going to delete all of
44:07:24
them because they never existed for us and our uh shr boundary actually shrinks even further.
44:07:31
And after that we start going in the upwards direction. But notice over here we don't have to care about these nodes
44:07:37
because we have already shrunk our boundary to only consider up until this point. Which means that we are going to
44:07:44
add this values 9 and five and again shrink our boundary.
44:07:50
And then we will add this value six and seven. Again shrink our boundary.
44:07:56
Add value number 11. And then again shrink our boundary.
44:08:03
And in the end we are only left with one value number 10. And we will add it to our answer. And this would be the answer
44:08:10
that we need to return. So this solution works perfectly fine. We don't have to bother keeping track of the number of
44:08:16
nodes visited because we are shrinking our boundary with every single iteration. And let's see that what are
44:08:22
the pros and cons of this one. So first of all we will try to calculate that what is the time and space complexity for this one. So time complexity is
44:08:28
actually going to be bigo of m cross n by m cross n because we have to iterate all the nodes inside the given matrix.
44:08:35
So that is a given thing. Now in terms of space complexity we are actually doing it in a constant space complexity
44:08:41
like you can't consider this answer to be a space complexity because anyways we have to return a list of uh all the
44:08:47
nodes that we have traversed. So that is part of the answer that is not part of our algorithm and that is why this is a
44:08:55
very good approach and you can discuss with your interviewer that if he is okay with this approach you can also move
44:09:00
forward with this one. Let me show you what would be the second approach.
44:09:08
So for the second approach we are actually going to keep track of the visited cells and also the boundaries and whichever we hit first we are
44:09:15
actually going to change our direction. So one thing remains common is that we are always going to traverse in the same
44:09:21
sequence of direction. So first of all we'll traverse in the right direction then we will go in the downwards path then we'll go in the leftwards path and
44:09:27
then we'll go on the upwards path. So this will remain common and then we keep on repeating and at any moment we hit
44:09:35
either a visited cell or we hit a boundary. Originally we are at this position number uh 1 and we are going to
44:09:43
mark all the coordinates of the matrix. So the coordinates of the matrix is going to be 0 1 2 3 and 0 1 2 3. Now
44:09:51
current position of this one is actually 0 0. We can see over here. So what we are going to do is we are going to
44:09:57
create a hash set and inside the hash set we are going to first of all check
44:10:02
that whether the coordinate that we are visiting have we visited it already or not. If we have not visited it we will
44:10:09
add an entry to our hashet. So at this position number one we will add an entry to our hashtag saying that okay
44:10:14
currently we are we have we have already visited this coordinate number 0 0 and we are also going to create our answer
44:10:21
list and inside the answer list we are going to mention all the nodes that we have traversed which we need to return in the end. So we will add the center
44:10:28
number one on and then we will keep iterating on this direction on the right side until we hit either a boundary or a
44:10:34
visited node. Remember either a boundary or a visited node both the things we are keeping track of. So and at the same
44:10:41
time we are going to add all the entries. So in this case we will we would have added entries like 0 0 0 1 0
44:10:46
2 and 03 all the things we have added we have also added it to our answer that we
44:10:52
have already traversed this nodes 1 2 3 and 4. And now we know that we since
44:10:58
because we have hit a boundary it is time for us to go in the downwards direction. So again we will go in the
44:11:04
downwards direction until the point we hit a boundary and we would have also added all the values to our hash set as
44:11:09
well again and also to our answer list as well like I'm not bo going to bother writing all of them but I can understand
44:11:16
that you are smart enough to understand that again we go on the leftwards direction until the point we hit a
44:11:21
boundary and again we start going on the upwards direction but notice that when we are going in the upwards direction we
44:11:28
are actually going up until this point number five we are adding all the values to our hashet we are also adding all the
44:11:34
values to our answer. Now at this five when we go try to go this position
44:11:39
number one we would have ident we would first check that okay whether this position number one which is located at
44:11:46
the coordinate 0 0 have we visited it already or not and we would identify that okay the 0 0 has already been
44:11:51
visited which means that because it has been visited we actually don't need to
44:11:57
uh go on go and do that again what we need to do is change our direction. So
44:12:02
at from this position number five again we would change our direction in the same manner where would have ch where we
44:12:08
would have changed our direction if we would have encountered any boundary. So
44:12:14
uh then again we will add all those entries six and seven and again add them to our hashet and then we keep iterating
44:12:21
until we reach to the end of all the entire matrix and we would have visited all of them. Now this solution works
44:12:27
perfectly fine. Now but the thing is you would immediately say that hey uh this solution actually we are using an
44:12:34
additional hashet which means that for the space complexity we are actually using big go of m cross n space
44:12:39
complexity which means how come this solution be can be better. This is actually a bad solution. Uh so your
44:12:46
interviewer is definitely going to let you know that okay you don't you can't use this hashet to keep track of all the
44:12:52
visited nodes. uh in this case what we are going to do is there is another solution to solve this problem without
44:12:59
keeping track of all of the visited number of nodes.
44:13:04
So at any position if we have visited some node what we are going to do is we are going to add it to our answer list
44:13:11
first and then we are going to change its value and how we are going to change its value we are going to put something
44:13:16
random that is out of bounds or it doesn't even make sense. Uh so over here
44:13:21
suppose we are at this position number one and then we start traversing this 1 2 3 4. So we have traversed 1 2 3 4. we
44:13:28
have added it to our answer and then at the same time the moment we uh we are
44:13:34
done with traversing through any node we are actually going to change its value to something let's say uh minus 100 or
44:13:42
let's say value number false or something like that right anything that is not part that can never be a part of
44:13:48
this matrix and we need to replace our value with this one so let's say let's say in this case we replace our value
44:13:54
with this minus 100 considering that this would not be a part of this matrix like it can be and then you can change
44:14:01
this value. You can discuss it with your interviewer and then again we start iterating in the same fashion. So again
44:14:07
we would have added all the values to our answer list and again we would have changed all of its values to whatever
44:14:13
the value we decided and we are going to keep repeating the same work up until
44:14:20
this point. And notice that at this position number F5 when we try to go upwards we are going to check that okay
44:14:26
if the value of this particular cell if that is not minus 100 then only we can
44:14:32
say that okay this node has not been visited and then only we will add it to our answer but the moment we find out
44:14:38
that okay this value is actually minus 100 which means we have already visited this node and added to our answer
44:14:43
already. So now we have to change our direction in the same manner where we would have changed our direction if we
44:14:49
had encountered any boundary and then we would follow the same path and we would
44:14:55
be able to solve this problem. So if we see the time and space complexity in this case the time complexity is also
44:15:00
going to be big of m cross n and the space complexity is actually going to be bigo of one constant time space
44:15:08
complexity. Now you would argue that the issue with this approach is that we are
44:15:13
actually changing whatever the given input is and that is not a bad practice that is not a good practice in when you
44:15:20
are actually doing inside the job but when you are giving any competitive coding interview your interviewer might
44:15:27
expect you to do it. So it's always good to know a better approach. Let's move on to coding now.
44:15:37
So first of all we are going to create an integer called visited and we are going to assign it some random value. So
44:15:42
let's assign 101. Uh also we are going to create two variables to keep track of the number of rows and number of columns
44:15:49
we have. After that we are going to have couple
44:15:54
of variables to keep track of the row position and column position we are at and we are going to initialize it to
44:16:00
value number zero. Now we have to iterate over our four directions. So we are going to create a 2D array. Uh we
44:16:07
are going to name it as directions and we are going to iterate over all the four directions. So we are going to have
44:16:14
four coordinates that would be used to go to any direction we want to
44:16:20
and we are going to maintain a sequence uh where the first would be to go to right then next would be to go to down
44:16:26
then left and then up. Now we need to keep track of what is the
44:16:32
current direction we are at and when we need to change the direction. So we are going to initialize couple of variables
44:16:38
uh called current direction and the change direction and we are going to assign the value zero to both of them.
44:16:45
So we will have to create an array list to store the result. So we are going to initialize a list of integers to store
44:16:54
the answer. Uh inside the inside our answer we are going to add the first node of our
44:17:00
matrix which is located at position 0 0. And after that uh remember every time we
44:17:07
we go through any value we will have to update that value inside the matrix because I am showing you the
44:17:14
implementation for the second approach I showed in the explanation video. So we will update the value of this matrix
44:17:20
node to this visited element that we already set up. Now we will start iterating over our
44:17:28
given matrix and we are going to have few conditions. So first thing is we need to iterate over the given matrix.
44:17:35
Also we have to iterate over in a particular direction and the moment we encounter a condition where we are
44:17:42
either reaching a boundary or reaching a visited node we will have to change the direction. So we are going to use
44:17:48
current direction and change direction and make conditions around them. So
44:17:53
first first of all we are going to have a while loop that while the change direction is actually going to be less
44:18:00
than two and why less than two because we are we have four directions and at
44:18:05
any point we can only go in one direction and when we are the maximum
44:18:11
amount of patterns we have is either we can go on right down or left up path and
44:18:18
that is what we are going to use. Once that is done, we will have another while loop that takes care of all the possible
44:18:26
ways where we need to restrict our matrix. First four conditions would be to check what that whether we are
44:18:33
hitting a boundary and the last condition is to check that whether we are hitting a visited node or not.
44:18:41
If none of this is true, first of all, we will have to reset the change
44:18:46
direction to zero because we are not breaking any direction. After that, we
44:18:52
are going to update the value of row and column.
44:18:58
Then we will add the current matrix row and column position to our answer array
44:19:04
list. And then we will update that value for that particular row and column position to visited uh value.
44:19:12
And after first loop ends we will have to update the values of the current direction and change direction. So for
44:19:18
the current direction we are actually going to add a value and then we are going to modulate by four
44:19:26
and we will have to update the value of our change direction.
44:19:31
And after both the loop ends uh basically our answer error list should have all the elements and we would have
44:19:38
traversed the matrix. So we can simply return that. Let's try to run this code.
44:19:44
Okay, seems like our solution is working. Let's submit this code. And our code actually runs 100% faster
44:19:51
than all the other solutions which is pretty nice. Also, I have created a GitHub repository where I have been
44:19:57
where I'm storing all the problems that I have solved so far and you can go to any problem and you would be able to
44:20:03
find the Java solution for that and you can use it. It's quite helpful and uh I
44:20:09
would be posting this link in the solution as well also this uh solution in the comments as well. So, you can
44:20:14
check it out from there. Thank you.
44:20:26
Hello friends, we are some not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to do rotate image lead code
44:20:32
problem. And this problem actually has very real practical applications as we know that there are bunch of different
44:20:38
softwares that allows the option to rotate an image. And if we see the list of companies where I want to join in and
44:20:45
already have asked this problem, uh there are companies like Facebook, Microsoft, Amazon, Apple, Google,
44:20:51
Bloomberg, Uber, Tik Tok, Nvidia, eBay, PTM and Robin Hood. So that's why I'm
44:21:00
paying my utmost attention. I hope you also enjoy the video. This is a lead code medium problem and basically we are
44:21:06
given an n + n 2D matrix which represents an image. Now we need to rotate this image by 90° clockwise. Also
44:21:14
one more thing that is mentioned that we need to do it in in place. We do not need to use an additional 2D matrix to
44:21:20
solve this problem. So the space complexity has to be constant in this case. Let's uh try to see it with an
44:21:27
example. So over here we are given a matrix like 1 2 3 4 5 6 7 8 9 and we can
44:21:33
see that this particular row is actually converted to this column which means that all the nodes have been transported
44:21:40
to 90° which means this one has gone to this place this two has gone to this place and this three has actually gone
44:21:45
to this place and same goes for all the other elements that this four has actually gone to this place which we can
44:21:51
see over here and this seven has actually actually gone to this place which we can see over here and the same
44:21:57
way it is shown in this second example.
44:22:02
Okay, suppose this is the input matrix we are given which means that this is the answer for the 90° rotated matrix.
44:22:10
Now notice couple of interesting things in both of them. Well over here the value 1 2 3 is in a row. So over here
44:22:18
this value 1 2 3 is actually in a column. Same goes over here that this value 456 is in a row but this 456 is in
44:22:24
in a column. And same goes for the 78 9 78 9. So this is a clearly a pattern over here. And basically what we can do
44:22:32
it is that if we somehow convert this input to replace all the values that are
44:22:39
inside the rows to be inside the columns and then reverse those entries. So
44:22:45
reverse all the rows. We would actually get a 90° rotated array. And let me quickly show you how we are going to do
44:22:50
it. Okay. So suppose this is the original input. I have drawn it much bigger over here. And now what we are
44:22:57
going to do is for every single row we are going to place it inside the column and every single column we are going to
44:23:02
place it in the row. Which means that currently at uh if we consider this position position number two. If we see
44:23:08
the I and J location this is this two is actually located at the position 01
44:23:14
representing these two values. So what we are going to do is we are going to flip the values of this zero and one and
44:23:21
same we are going to do this for this four which means that this four will come to this place and this two will come to this place. The thing they did
44:23:28
for this two and four we are going to repeat for all the other characters and then we would have an array which would
44:23:35
have where all the rows would have been converted to all the columns. Also there is a name for the process of converting
44:23:42
all the rows to all the columns and that is actually called transposing a matrix.
44:23:47
So first of all we are going to transpose this original given input matrix and we will see that the result
44:23:53
would look something like this. So uh this one will remain at the same
44:23:58
position because this 0 0 is at the correct place. So we don't we can't change anything. Now this two is going
44:24:04
to be replaced by this four which means that over here we would have two and over here we would have four. Again this
44:24:09
three is going to replace by this seven. So over here we would have seven and over here we would have three. So if we
44:24:15
just notice right now this row 1 2 3 has actually been converted to a column and this column 147 has actually been
44:24:22
converted to a row. We are going to repeat the same process now. And now uh this five will not have any impact
44:24:28
because the position is actually 1 one. But for the six and eight we will actually have to swap their values that
44:24:35
now over here we would have the value number eight and over here we would have value number six and this 9 will remain
44:24:41
at the same position because the value is 22 which means we can't do much about it and now uh basically now we have
44:24:49
created all the rows and converted them to different columns. Now the next idea is that we are going to put this in the
44:24:57
reverse order. And if we reverse the rows for this transposed matrix, we can
44:25:02
clearly see that we would get a 90° rotated answer. Uh let's do that. So
44:25:07
over here the values would be 7 41. If we reverse this particular row, same
44:25:13
thing we will do for this one. So the answer is going to be 8 52. And again
44:25:18
for this one the last row the answer is going to be 9 63. And if we see this is
44:25:25
actually same as the answer we had achieved before. And I'll just draw all
44:25:31
these three different matrix to give you an example that how we are going to do the things. But basically all of this
44:25:36
activity can be done in place in inside the single matrix. All we will have to do is we'll have to use a temporary
44:25:43
variable to first of all swap the elements in this fashion and then once
44:25:49
that is done we will need a temporary variable to replace the values uh inside
44:25:54
the given matrix and reverse the rows. Uh if we see the time and space complexity for this approach basically
44:26:01
for the time complexity we are actually we will have to iterate over all the elements inside the given node to create
44:26:07
this transpose matrix. And once the transpose matrix has been created, we will have to reverse all the elements.
44:26:13
Which means that the time complexity in this case is going to be big of n cross n. But we will have to repeat this
44:26:19
process two times. So which means we can say that bigo of n cross n * 2. But in
44:26:24
general we can just write it as of n + n. And this would be our solution. In terms of space complexity as mentioned
44:26:31
earlier, we are not using any additional space which means we are doing it in a constant space complexity. And this is a
44:26:37
very good solution. Any interviewer would be really impressed with your approach and this works for all the
44:26:42
different n + n matrix. Now let me quickly show you another solution for the same problem where we don't need to
44:26:50
do like this transposing activity and we can actually solve this problem in a single go.
44:26:59
So for the second approach we are going to do things a little bit differently. First of all I have drawn over here bunch of different matrix of different n
44:27:06
size. So n is equal to 1 2 3 and 4 I have shown you. And now we are going to see that if we rotate the 90° can we see
44:27:12
some patterns over here. So suppose we have a matrix of the size number one. If we rotate this 90° it makes no sense.
44:27:18
It's the value is going to still remain same. So we are going to keep it as one. Now for this n is equal to 2. If we
44:27:24
rotate this matrix by 90° actually the thing is going to happen is that this one node is going to shift one value to
44:27:31
the right. This two node is also going to shift one one value to the right. three uh four and three all of them are
44:27:37
going to shift one value to the right and the answer in this case is going to be okay. So first of all we'll shift one
44:27:43
over here one value to the right two and then four and then three. So this is the 90° rotated angle for this n is equal to
44:27:51
two. So basically what we have done is we have rotated all the values one place to the right. Okay for the outer layer
44:27:58
and in this case since we only have four elements which means the layer is only one we are good. So when when we get to
44:28:05
this n is equal to 3 things becomes a little bit interesting and interesting how because we have the cells located on
44:28:12
the outer layer and we have one cell that is located in the inner layer. Now when n is equal to 1 when the number of
44:28:20
cell that is located inside the inner layer we know that the value is going to remain same. So even if we 90° rotate
44:28:26
this particular element it is still going to fall over here on the same place. We are not going to do anything
44:28:32
special with this one. But for these other values we will going to apply the same logic we applied over here where
44:28:38
over here where because n was two we had to rotate all the values one degree to the right or one place to the right. In
44:28:45
this case because n is equal to 3 we are going to rotate all the values to the two two elements to the right. Okay. And
44:28:53
this would be the answer. So if we see in this case this one is going to come
44:28:58
at this place. This two is going to come at this place. This three is going to come at this place. And same thing is going to keep on repeating for all the
44:29:05
other elements. And that is how we are going to find uh its solution. So let me quickly draw the solution for this outer
44:29:13
layer over here. This is the answer for the outer layer
44:29:18
of this matrix. And because in the inner layer we only have one element and for one element we don't have to do anything
44:29:24
special. The five is going to be at the same place and this is going to be the solution that we rotated all the
44:29:30
elements couple of places to the right. Now in this case n is equal to 4. So obviously for the outer layer you can
44:29:37
imagine that the pattern we are going to follow is going to be the same that we are going to rotate all the elements
44:29:42
three steps to the right. Okay. So that is clear. But for this inner layer we can actually
44:29:50
see that this time we have a set of four values which means we have a 2 +2 matrix
44:29:58
inside. So over here we are going to use the same logic we used over here where we are going to rotate them one step on
44:30:05
the right. So first let's do it for the outer layer and then we will do it for the inner layer.
44:30:11
So the rotation for this outer layer is completed. Now for this inner layer we will have to rotate them one times based
44:30:18
on whatever we have seen when n was two. So we are going to do the same thing.
44:30:23
This is the answer of 90° rotated angle. Which means one thing we can see over
44:30:30
here is that we can have four pointer starting at this 1 4 16 and 13 and
44:30:36
rotate all these values in place by using a temporary variable. Once that is
44:30:42
done, we can repeat the same process for this value number 2 8 uh 15 and 9. And
44:30:50
again we will keep on rotating them sequentially at the same time in place
44:30:56
and then we would be able to fill out our outer layer. Once that is done we
44:31:02
will come inwards and we will start filling the inner layer based on whatever the number of n we have and
44:31:08
that is the approach we are going to take. Okay. So suppose we have a 3x3 matrix and I'm going to show you what is
44:31:14
the approach we we are planning to take. Now this additional matrix I have drawn that is only for the understanding
44:31:20
purpose. Actually we are going to do everything in just one single matrix but I'm just going to show you that what are
44:31:26
the value changes happening and how we are going to use this temporary variable to fix our problem. So first of all we
44:31:32
are going to store the value of this one inside our temporary variables. Okay. So the value inside the temporary variable
44:31:38
is one. Now what we are going to do is first of all we are going to project this value number seven to this place
44:31:43
one. So this becomes seven and this becomes seven. Currently this is the scenario. Now we are going to project
44:31:48
this value number nine over here which means that this seven is going to be replaced by value number 9 and this is
44:31:55
also 9 at this at the current moment. Again we are going to project this three to this 9 which means that the value of
44:32:02
this 9 is going to be replaced by three and this is going to remain three. And now at the final moment we are going to
44:32:09
take whatever the temporary variable we had and we are going to put it in this place which means that this value is
44:32:15
going to be one. So at a single iteration we have actually shifted values of all of these four places in
44:32:22
its correct position. Again we are going to repeat the same procedure for this these four values which means that over
44:32:29
here now the we are in the next iteration. Now the value of the temporary variable is two. Now because
44:32:34
the value of the temporary variable is two. First of all we are going to project this value number four to this
44:32:40
place number two which means that currently both values are going to be 44. Then we will project this value 8 to
44:32:46
this four which means that this is already eight and this value becomes 8.
44:32:51
Then we will project whatever value of six we had at this position number eight. Which means that this value would
44:32:56
become uh six and this is already six. And at the end we are going to take whatever the temporary variable we had
44:33:03
we are going to project that value over here. Which means that this six is going to be replaced by this value number two.
44:33:11
And once that is done essentially in two iterations we have taken care of all the values that were placed out in the outer
44:33:18
layer and we are done with this one. Now only thing we need to consider is this inner layer and because the for the
44:33:23
inner layer n is equal to one which means that we can basically leave the value as it is and this is the answer
44:33:30
and this is how we are going to able to rotate the the entire element in 90° in
44:33:37
just like very few iterations. Uh we don't have to do like transpose matrix and then place the replace all the
44:33:44
values and change all the values. So even if we see the time and space complexity in this case the time
44:33:49
complexity is going to be bigo of n cross n but the we only have to do it
44:33:55
single times and space complexity is going to be bigo of one because we are only using an additional temporary
44:34:01
variable to store some values. Apart from that we are not using anything special to store any values.
44:34:10
So we will initialize a variable called n and we are going to store the length of the matrix for this one.
44:34:18
Once we have that we will have to iterate over this given matrix and we are going to create two for loops to
44:34:24
iterate over this given matrix. Now remember we only have to iterate over half of the matrix. We don't have to do
44:34:30
much work which means that we are not going to iterate from int i is equal to0 to i is equal to n. We are actually
44:34:36
going to do it i is less than or equal to n + 1 by 2. Now you will ask that why n + 1 by 2 because in the condition
44:34:43
where the given n is odd number we will have to take care of that scenario as well.
44:34:52
So first of all we are going to create a temporary variable and we are going to store value of one of the elements inside the stem variable and then we
44:34:58
will start working on the flip operation for the remaining three elements.
44:35:04
Once red is done, we will start iterating over all the elements.
44:35:11
And once this loop ends, basically we would have rotated our matrix 90° angle for all the elements. Now the question
44:35:18
comes that how did I get this value of I and J. Actually I could explain it to
44:35:24
you but I would expect that you draw the any 3x3 or 4x4 matrix on paper and try
44:35:31
to see that how we are getting this these values of I and J because that would be a very good exercise for you.
44:35:36
Anyways I would be posting this code in the solution so you can you would be able to check it out but still I would
44:35:42
expect that if you do it by yourself you would not never be able to forget it. Now let's try to run this code. Okay,
44:35:48
seems like our code is working. Let's try to submit this code and taa our solution is actually 100%
44:35:56
faster than lot of other solutions and uh basically we are solving this problem pretty efficiently again I would be
44:36:03
posting this in the comments so you can check it out from there and there I would ask you to figure out that how we
44:36:09
are getting these values of i and j compared to this value of n and that would be a really good exercise for you
44:36:15
to do at
44:36:27
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better at technical interviews. Keeping with
44:36:34
that goal in mind, today we are going to do a very interesting lead code problem called valid sudoku. Now if we see some
44:36:40
of the popular companies who have already asked this question there are companies like Amazon, Apple, Nvidia,
44:36:45
Uber, Microsoft, Facebook, Google, Bloomberg, Door Dash, Goldman Sachs and
44:36:50
Snapchat. So that's why I'm paying my utmost attention. I hope you also enjoy the video.
44:36:56
So this is a lead code medium problem and also very well-like problem on lead code. In this problem basically we are
44:37:01
given a 9 + 9 sudokco board and we need to determine that whether this given sudokco board if that is valid or not.
44:37:07
Now uh we are told that only filled cells needs to be validated according to
44:37:12
following rules and we are given three rules to determine that whether the board is valid or not. First rule
44:37:18
dictates that each row must contains the digits between 1 to 9 without repetition. This is the key phrase that
44:37:25
there should not be any duplication. First rule defines that every single row must have unique characters from 1 to 9.
44:37:32
Second row defines that every single column must have unique characters between 1 to 9. The third definition
44:37:38
shows that uh the box of 3x3 or the subboxes in the grid must contains the
44:37:44
digit 1 to 9 without repetition. So this is a little bit tricky one but basically amongst the 9x9 box we can make nine
44:37:52
different 3x3 boxes where the values 1 to 9 should be present without any
44:37:57
repetition. Now we are told that the sudoku board in this case is partially filled and we need to only check the
44:38:04
boards based on the filled items nothing more than that. So it could be possible
44:38:09
that we cannot be able to complete the entire sudoku. But given the filled elements if they are at least behaving
44:38:17
these three definitions that are mentioned where every single row, every single column and every single box they
44:38:24
all should have 1 to nine unique elements. then we can determine that this solo sudokco board is valid. If it
44:38:30
is not the case, then we can determine that this is not valid. So if we take a look at this particular example, this is
44:38:36
the example of a valid sudokco box. And what makes this sudokco box valid is that that every single row or all
44:38:43
amongst all the nine rows, the filled elements are filled in a manner that there is no repetition between 1 to 9.
44:38:50
Now if we just see take one example say for an example for this first particular row if I add one more five over here
44:38:58
then it make it completely makes this pseudo code invalid because the elements five is repeated two times in this
44:39:05
particular row. We are not concerned with the empty cells because we can determine that that can have any
44:39:10
particular value but if there is a five or any duplication present over here we can determine this to be invalid. But
44:39:16
let's just say that five is not present over here. So we are good. Same way if I just put an eight over here in this
44:39:22
middle portion and then this column would be invalid and uh that would make
44:39:28
this entire sodoku box invalid. So that is also one more thing that we need to
44:39:33
take care of and the third and little bit more complicated thing is the boxes that we need to be concerned with in
44:39:40
this case. So there as we can see from this image there are actually nine boxes
44:39:45
present in any given sudoku board and we need to determine that 1 to nine values are remain non-duplicated for all of
44:39:53
them. So basically say for an example for this particular box now this box
44:39:58
currently only has one value six which means this this box is valid because there is no duplication but if I add one
44:40:04
more six over here which means then then the six is repeated two times so that would make it invalidated. So basically
44:40:10
we need to take care of rows, we need to take care of columns and we need to take care of boxes for this particular
44:40:16
problem to solve them. Basically I'm going to show you three different solutions. One for the row, one for the
44:40:23
column, one for the boxes and then we will find a way to combine all three of them. So say for example this is the row
44:40:29
we are given right now. We are only considering one row for now because same solution can be applied to all the
44:40:36
remaining nine rows. So that is a trivial fact. So basically first we will try to determine suppose this is the row
44:40:43
we are given. What is our objective? Our objective is to make sure that all the filled val values over here they are
44:40:50
unique between 1 to 9 and there is no repetition. So the simplest way to do
44:40:55
this is to create a hash set. So if I create a hash set currently this hash set is empty. Maximum possible length
44:41:02
this can have is going to be nine because there are only nine cells in any given row. Okay. Now the logic we are
44:41:09
going to use is that first we are going to iterate over the row. If the value there is some value we will try to first
44:41:16
check that whether that value is present in the hash set or not. If it is not present then we will add that particular
44:41:23
value in the hash set and move on to the next element. If the value is already present which means that there is a
44:41:28
duplication we find and then we can simply return false that this given sudoku board is invalid. So let's try to
44:41:34
do that. First we will have we are at position number one. Currently there is nothing in the hash set. So there is
44:41:40
because there is no value we will add entry one over here and we can determine that this node has been visited or this
44:41:45
cell has been visited for the row perspective and there is nothing wrong we find. Now this one is a dot. So if
44:41:51
there is a dot or if there are no values we can simply skip over that because that is none of our concern. We are only
44:41:57
concerned with the elements that are already filled. Now the next element is three. So we will add an entry three
44:42:02
over here because three was already not present. This one is again empty. This one is value number six. We will add six
44:42:07
over here. And then same way we will add two over here. And these two cells are not empty. So we have reached to the end
44:42:14
of the row. Which means we can determine that this particular row is currently valid. And there are no issues with
44:42:19
that. But say for an example for this last cell rather than uh adding this
44:42:25
value if we had one more value number three over here then what would happen? Once at this position when we add value
44:42:31
number two over here now we are over here. This one is a filled value. Because this is a filled value, we will
44:42:36
try to see that whether this value is present in the hashet or not. Since this value is already present, this is a big
44:42:42
no no. And we found a duplicated entry which means immediately we can call this entire pseudokco board invalid because
44:42:49
we find an in invalid row. So that is how we are going to determine the rows.
44:42:54
Now currently this one only had one row. So we use just one single hashet. Say for an example we were dealing with nine
44:43:01
different rows. If that was the case, what we would have to do is we would simply have to create nine different
44:43:07
hashets and uh basically for every single hashet, we are going to repeat the same process. So this is just
44:43:13
repeating the same process for different set of inputs. Uh if the given sudokco board is let's say 16x 16, we would have
44:43:21
like had 16 hash sets but still the core concept would remain same. Now this the
44:43:27
way we've solved for the box the same way we can actually solve for the columns. Again for the columns we are
44:43:33
also going to create a hash set. So say for an example this is the column we will create the hash set and we will
44:43:39
repeat the same logic. So currently this value number one is not present. We will add value number one over here. This
44:43:44
three is not present. We will add three. Same way we will add six and we will add two. And now we are at the end of this
44:43:49
column and we didn't find any duplicated entries. So we can uh say that this particular column is valid. And then we
44:43:55
can move on to the next two column. And same way for the next column we would create a new hashet. And if any point in
44:44:01
time we find duplicated entries. So say for example for the second column we have two values one and one over here.
44:44:07
First we would add this one over here. Then the moment we move on to the next value and we see that hey in the hash
44:44:13
that one is already present. We can say that okay this particular column is invalid and that is why this entire
44:44:18
pseudoco board is invalid. So this is also a very simple thing to understand. Same logic we are using what we used for
44:44:25
rows we are going to use for the columns. The thing is for the box. Now for the box this is a matrix kind of a
44:44:32
structure. Okay. And for the matrix kind of structure again our main logic or the
44:44:38
thing we need to achieve is going to remain the same that we need to make sure that there are no duplicated entries for the filled values between 1
44:44:45
to 9. So again even for the box we would be able to create a simple matrix or or
44:44:50
a simple hash set. Now for the seven hashet we are going to apply the same logic and we would keep adding the
44:44:56
entries uh until we find any duplicate entries and if we find duplicated entries we will call it invalid. So this
44:45:03
is a very simple thing to do but the tricky part is okay now say for an
44:45:08
example we need to determine for rows and columns okay currently say for an example we are just ignoring the boxes
44:45:15
for now we are only considering that how to solve this problem for just row and columns and we need to find that we
44:45:21
don't find any duplication between 1 to 9 for every single row and every single column how we are going to achieve that
44:45:26
we are going to achieve that in the same manner I explained earlier the only logic we are going to use this is that
44:45:33
we are going to create nine hashets for rows. Okay. So for rows we are going to
44:45:38
create nine hashets. Every single row we are going to check for the duplicated entries. If we find any duplication we
44:45:44
can return invalid immediately. If we don't find the duplication we will move on to the next row and we will keep on
44:45:51
repeating the same process. The same thing we are going to use for the columns as well that even for the
44:45:57
columns we are going to create nine hashets. So uh again and we are going to repeat the same process to check that
44:46:04
whether there are any duplicated entries or not and since there are none in this particular case we can simply in the end
44:46:10
return the answer valid. Now remember we only solve this problem for the rows and
44:46:16
columns. Okay but the thing is we need to take care of the boxes as well. Now for the boxes there is just one tricky
44:46:23
part and the trick tricky part is that actually for the boxes it is not as
44:46:29
simple as the just the correlation between row and column because for rows we had the particular separate entries
44:46:36
for every single rows that we can traverse over them or determine them pretty easily. Even for the columns we
44:46:43
have the direct way to identify that whether this is a column or not. But when it comes to the boxes, we need to
44:46:50
establish a correlation between the set of uh different rows and different
44:46:55
columns. And how would we be able to achieve that? Okay, so even for the boxes basically we need to create nine
44:47:01
hashets. Well, the thing is how do we define which number goes where? So basically these are going to be all the
44:47:09
boxes that we need to create. Okay. And these are the nine boxes. But the thing is how do we able to define the nine
44:47:16
boxes? The answer is quite simple. We are actually going to do a division by
44:47:22
three for any particular row value and any particular column value. So that would be a very clear indicator on what
44:47:30
box we need to choose and let me give you a quick demo. So basically the idea is that okay currently this row position
44:47:36
is 0 1 and 2. Okay. Now say for an example if we do like 0 divided by 3 what is the value? We are going to get
44:47:42
0. Of course if we do like uh 1 divided by 3, what is the value we are going to do? We are actually going to consider
44:47:49
the floor value. Okay, not the ceiling value. So if we consider the floor value, 1 divided by 3 is going to be
44:47:54
like 0.33. So basically in the integer it is going to be zero. So these three
44:47:59
values are going to represent zero. Same way these three values are going to represent zero. Which means if we are
44:48:07
iterating over any of these cells, we can say that we need to consider box number zero for that. So that is pretty
44:48:14
good. Same way if we are going over any other these three or these three values.
44:48:20
So okay this is going to be 1 1 and 1 because if we divide divide them by three and same way this is going to be 1
44:48:27
1 uh if we divide them by three. uh same way this is going to be 222 and same way
44:48:33
this is going to be 222. Now say for example we are at any cell amongst this particular box. Now we need to identify
44:48:40
that which particular hashet to select. Now this one is going to be box number six. So hashet number six we need to
44:48:47
select. Okay. But how do we define this hashet number six is going to be the correct one. And this is where we are
44:48:53
going to use this formula where for any particular cell position we are going to
44:48:58
do this formula where we are doing row divided by 3 plus we are doing three and
44:49:07
plus we are doing column divided by 3. Okay. So this is the formula we are going to use to determine that what is
44:49:14
the correct correct box number. Now suppose for this particular formula suppose we are at this particular uh box
44:49:21
or this particular cell. Okay. Now if we take a look at this particular cell currently the row is going to be uh row
44:49:28
number four. Okay. Row is four and currently the column position is going to be 7. Let's apply this particular
44:49:35
formula for this row and column position. If we do that we are going to do 4 / 3 + 3 + 7 / 3. Okay. So in this
44:49:45
case 4 divided by 3 is going to give us the answer number 1 + 3 and + 7 divided
44:49:51
by 3 is going to give us the answer two. If we do sum of these three values we are going to value we are going to get
44:49:57
the value of six and this six is going to determine that the box currently if
44:50:03
we are at this particular position we need to check it against hashet number six. This is the only complicated matter
44:50:11
for this particular question. If you are able to identify a way to find the correct box then this is a very simple
44:50:17
problem to solve and which we just did. So this is the whole logic and basically
44:50:23
now we know that how we are going to solve for row plus column plus box. The
44:50:30
idea is that for row we are going to use nine hash sets. For column we are going to use nine hash sets and even for boxes
44:50:36
we are going to use nine hash sets. And uh we already know how to determine what
44:50:42
is the correct box we need to look at. And based on that we simply need to check for the duplicated entries. If we
44:50:49
find any duplication we simply get rid of it. If we don't find any duplication awesome then we can conclude this given
44:50:57
sudo code to be valid. And this is the whole optimal solution. Now if we see
44:51:02
time and space complexity for this one the time complexity is actually obviously going to be big of n² and why
44:51:09
n² because we are given n to be same for both rows and columns. So that is why
44:51:14
this is going to be big of n square. If we see space complexity now this one is like a debatable question because we
44:51:22
already know that we are going to use 27 additional hash sets. The thing is why did we come up with this number 9?
44:51:29
Because the we are given n is equal to 9 by 9 matrix. So we are given n is equal
44:51:34
to 9. So that is why this 9 came in. So basically space complexity is going to be big of 3 n. So in general we can
44:51:41
write this to be of n. But if we are explicitly told that we are only going to use nine boxes then we can also
44:51:48
conclude this to be a finite number and this could also be considered as constant. So if you do this discussion
44:51:55
with your interviewer that you are going to look very uh clear in your concepts regarding time and space complexity
44:52:06
since this is already pretty long video and the coding is just a bunch of repetition. So I am just going to
44:52:11
explain you the code and then I'm going to paste this in the comments so you can check it out from there. So first of all
44:52:16
we are going to create an array of hashetss. Uh so first we are going to create an array for row. Second we are
44:52:23
going to create for column and third we are going to create for the boxes. Uh and the size of this particular array is
44:52:29
going to be uh the size of 9 uh that is given over here and we are hardcoding this value because we are basically told
44:52:37
that this is going to be a 9 + 9 pseudo code. Now after filling these values we
44:52:42
simply need to initiate the hash for every single one of them. So we are going to just iterate over all the
44:52:48
values and we are going to initiate initiate the hash set to accept the character as the input. Now we are going
44:52:54
to run two loops. First is to iterate over the row and second one is to iterate over the column. And using the
44:53:00
two inner loops like one inside the other. We would be able to iterate over the given input matrix. Now the moment
44:53:07
we are iterating over the given input matrix first of all we are going to determine that what is the current
44:53:12
character at any particular position or any particular cell. Now if the value is
44:53:17
is dot or if there is no value we can simply continue and move on to the next element. But if there is a value we are
44:53:24
simply going to first do these things. First we are going to check that whether for this particular row or hash set is
44:53:31
this value already present. If the value is already present we can simply return false. If that is not present, we are
44:53:37
going to add the value to that particular row hash set. Same thing we
44:53:42
are going to do for the column that if the value is present, we are going to return false. If the value is not present, we are going to add that value
44:53:49
to that particular uh subsequent columns hash set and then we are going to apply
44:53:55
our formula where we are going to uh check for the particular box and then we
44:54:00
are going to check that for that particular box if the value is present we are going to return false. If it is
44:54:06
not present we are going to return the subsequent correct value. And basically if we get out of the loop we are simply
44:54:13
going to return true that we did not find any place uh where there was invalidity and we could have returned
44:54:18
false. So now let's try to run this code. Okay, seems like our solution is working
44:54:24
as expected. Let's submit this code and our code runs decently fast compared to
44:54:30
lot of other solutions in in terms of time complexity and also it is very convenient in terms of space complexity.
44:54:36
So I would be posting this solution in the comments so you can check it out from there. Also at the same time if you
44:54:42
want to check all the solutions that I have done so far I have created a public GitHub repository where I'm putting all
44:54:49
all of my answer and this is going to be a great resource for anyone who is trying to prepare for different tech
44:54:54
interviews. So I would be pasting this link in the comments ex as well. So you can check it out from there. Thank you.
44:55:12
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better
44:55:17
at technical interviews. Keeping with that goal in mind, today we are going to do a very interesting lead code problem
44:55:23
called game of life. Now if we see some of the popular companies who have already asked this question, there are
44:55:28
companies like Amazon, Bloomberg, Google, Door Dash, Microsoft, Snapchat and Facebook. Uh so that's why I'm
44:55:35
paying mad close attention. I hope you also enjoy the video. This is a lead code medium problem and
44:55:41
also very well like problem on lead code. Basically, we need to find the next state in the game of life. Now the
44:55:48
question is what is game of life? uh originally this has been created by a mathematician named John Halton where we
44:55:56
are given a board that is made of m cross n grid. So there can be like any 2D grid of m cross n cells. Now the
44:56:04
thing is we are given the initial state of a cell and the possibility is that
44:56:09
any particular cell can be a live cell. So that is represented by value number one or it could be a dead cell that is
44:56:16
represented by value number zero. Now the thing is we are given the original
44:56:21
cell in some formation and then we need to find the next state of the cell using
44:56:26
the rules that are provided by the game of life. So over here I am basically creating a table from these four given
44:56:34
rules and then we are going to use this table to see that what would be the next state in game of life and how would we
44:56:41
be able to solve this problem. Okay, first one is it's saying that any live cell with fewer than two live neighbors
44:56:49
dies uh in the next state uh due to the underpopulation. Okay, so if the current
44:56:55
state is live, so we just note this with value number one. Okay, so if the
44:57:00
current state is live and if the number of neighbors is less than two. Okay, so
44:57:06
the number of neighbors is less than two, then the next state is going to be zero or the next state is going to be
44:57:11
dead state. Now the next one is that if any live cell with two or three living
44:57:18
neighbors will live on to the next generation. Okay, so if the current state is one, if the number of neighbors
44:57:24
is either two or three. If that is the case, then the next state is going to be live for that particular cell. That is
44:57:30
good. Now the next third one is that any live cell with more than three live
44:57:35
neighbors would die due to overpopulation. So okay if the current state is live and if the number of
44:57:42
neighbors is greater than three. If that is the case then the basically the cell
44:57:47
is going to die and the next state is going to be zero. And the last one is
44:57:53
that if any dead cell with exactly three living neighbors would become a live
44:57:58
cell because of reproduction. So if the current state is going to be zero and if
44:58:03
the number of neighbors is exactly three then the next state is going to be one for that particular neighbor. These are
44:58:10
the only four rules that we are concerned with for our game of life. And initially we would be given an example
44:58:17
that looks something like this where on an M crossN grid we are given some values that represents live and dead
44:58:24
cells and we need to find the next subsequent states based on these four rules. So this is the whole ask of the
44:58:30
problem. Now let's try to see some examples. So if we see this first example, okay, let's see that what would
44:58:35
happen with each cell. So currently the position of this cell is zero. Okay, this is a dead cell. Let's see for dead
44:58:42
cell does it has three neighbors that are alive? No, that is not the case. Which means this will remain dead. Okay,
44:58:48
so this will remain dead. Now for this next particular cell, okay, currently this is live one. For the live cell, how
44:58:55
many live neighbors this has? This only has one live neighbor which means it is less than two live neighbor. So this
44:59:00
would also be dead. So this is going to be dead also for this one. This is already dead and again it will remain
44:59:07
dead. And also this one will this this one. Okay. So this is the important part. Now at this particular position we
44:59:14
do not need to see the positioning of the neighbor from this particular cell. We need to see the positioning of live
44:59:20
neighbors from this original cell. So this is important for this problem. So
44:59:26
even when we are at this position number one and we need to identify that how many number of live neighbors this has
44:59:31
we are going to refer over here not on this newly created state because all the states are going to change at the same
44:59:38
time here I'm showing you one by one but in originality it's going to happen
44:59:43
everything at the same time okay so in this case currently this one only has one live neighbor so again this one has
44:59:50
less than two live neighbors so since the number of live neighbors is less than two this way is also going to
44:59:55
become zero. Now let's try to solve for this next problem. Okay, in this next one, okay, this one looks very similar.
45:00:00
So I'm going to add one more one over here. Now in this case, okay, currently this one is zero. Let's see that how
45:00:06
many live neighbors this cell has. This cell currently has three live neighbors. Okay, if there are three live neighbors,
45:00:12
which means that this zero state has the possibility to become state number one.
45:00:17
So in the next state, this is going to become value number one. Okay. And in
45:00:23
the over here now this one this one has two live neighbors not three live
45:00:29
neighbors. We are not considering this portion. We are only considering the original pattern. So currently this one
45:00:34
has two live neighbors. If there are two live neighbors it will remain one. So this will remain one. Same goes with
45:00:40
this one. This has two live neighbors. So this will also remain one. And same goes with the last cell that the last
45:00:46
cell also has two live neighbors. So this is also going to remain one. And this is going to be the next state.
45:00:52
Let's try a little bit trickier example. So in this case, let's see that what is going to be the answer.
45:01:01
And this is going to be the next state. And this is the whole crux of the problem that we need to solve. Now
45:01:08
understanding this problem is more trickier than actually solving this problem because the solution for this
45:01:13
problem is actually quite simple and there are only like just few things we need to consider to make this more
45:01:19
efficient. Okay. So now we have our example that we are going to use to solve this problem
45:01:25
and we have the number of rules that is already given in the problem statement and now let's see that what is going to
45:01:30
be the solution. Now suppose if we want to solve this problem what are the things we are going to need? Well, first
45:01:36
thing we are going to need is that for every single cell, we are going to need the number of live neighbors. Okay, so
45:01:42
we would be able to calculate that using uh the just going over the grid. But in
45:01:47
the problem, we would be able to do it quite efficiently using just uh scanning through all the neighbors of any
45:01:53
particular cell. So that is not a difficult task to do. Now let's see that what would be the solution. Now suppose
45:01:59
we are at this particular position one. Now how many number of live neighbors this has? This one currently has two
45:02:05
live neighbors. Okay, if there are two live neighbors, this one is going to remain one. So, we don't need to do anything. Let's just keep this one as it
45:02:12
is. Now, for this particular one, this has three live neighbors. So, again, we are going to use this rule. So, this one
45:02:19
is going to remain as it is. Now, for this particular one, this also has two live neighbors. So, we don't need to do
45:02:24
anything. This one can remain as it is. So, currently this upper row is going to remain as it is. Uh now for this
45:02:30
particular zero now this zero is actually covered with all three ones which means that this zero needs to
45:02:36
become a value number one. Okay so now this becomes value number one. Now when we are at this position number one how
45:02:43
many number of live neighbors does this particular one has? Well okay let's count this one has 1 2 3 live neighbors.
45:02:50
Okay four live neighbors and also five live neighbors. The question is can I
45:02:56
call for this particular cell that it has five live neighbors? The answer is no. Why no? Because this particular one
45:03:05
was originally a zero and hence this will only have this should only have
45:03:11
four live neighbors not five neighbors because this cell I changed while I was iterating over. Now this is a problem
45:03:19
that we have to worry about and what hap what is happening is that while we are
45:03:24
iterating over the matrix we are changing the state depending on these four rules and it could be possible that
45:03:31
the rules that are being changed could impact the remaining cells on their uh
45:03:36
rules and we might end up with a wrong answer. So one possible solution for that is that rather than making changes
45:03:45
in place if we just create a duplicated grid for this particular cell which
45:03:52
contains the original uh original items. So say for an example uh suppose this
45:03:57
was the original input we are given and we need to make changes. So what we are going to do is uh first of all we are
45:04:04
going to create a duplicated entries and we are going to keep track of live neighbors. Okay. So let's just first
45:04:09
quickly create a duplicated entry. If I create okay so now I have created a
45:04:15
duplicated entry and now whenever I have to make the change I'm going to make change in this original box. But in
45:04:22
order to find that how many number of live neighbors exist I'm going to check on the box with the previous state. So
45:04:28
this is going to be the copied version and this is going to be the original version. And after I'm done making
45:04:35
change to all the original items, basically all I will have to do is just copy them over to the copied version and
45:04:42
then I would be able to calculate the next state of the original version. So that is how I'm solving the problem of
45:04:48
state changing by creating a duplicated entry. Okay. And now this becomes very easy. How very easy? Okay. So we already
45:04:56
iterated over this first row. The values are going to remain 111. That is common. That is good. Now we are at this current
45:05:02
zero position. So this one has three live neighbors. So definitely this is going to become one. Okay. Awesome. Now
45:05:08
currently I'm at this particular position one. And the number of live neighbors is it has
45:05:15
four live neighbors. So because it has four live neighbors, it has greater than three live neighbors. This would become
45:05:20
zero. So that this I can make change over here that this would become zero. For this particular zero, how many live
45:05:26
neighbors it has? It has 1 2 3 and four live neighbors. And now see over here
45:05:31
because I have this copied version I was able to come up with the value number four. If I was checking previously I
45:05:37
would have come up with the value number three and then I would have changed its state to one. But actually since this
45:05:43
has four live neighbors I would not need to do any changes to the state of this particular zero and I can keep it as it
45:05:49
is. Now I'm at this particular position zero. Okay. So for this zero how many how many ones it has? It only has one
45:05:56
neighbor. So we I don't need to do anything. For this particular zero, how many neighbors it has? It currently has
45:06:02
two neighbors. So I don't need to do anything. For this particular one, how many neighbors it has? Currently, it
45:06:08
only has one live neighbor. Meanwhile, over here, it shows zero, but actually it has one live neighbor. So the number
45:06:13
of live neighbors is less than two, which means this state is going to be changed to value number zero. So let's
45:06:20
see that from this particular original version we had, how many how many items
45:06:25
got changed? Basically, this got changed. So this became zero. Uh this also got changed. So this was originally
45:06:33
one uh zero and then it became one and this got changed. So this is how we would be able to solve the problem of
45:06:40
game of life just if we just create a copied version and then it becomes very easy for us to find the live neighbors.
45:06:47
Now the question is your interviewer is directly going to jump onto you saying that uh if we see time and space
45:06:54
complexity for this approach the time complexity is going to be big of m cross n why because we need to iterate over
45:07:01
the entire grid to calculate the result that makes sense but if we see space complexity the space complexity is also
45:07:08
going to be big of m cross n why because we are using this additional space to
45:07:13
create a new copied matrix and your interviewer is directly going to jump and saying that can you solve this
45:07:20
problem with big go of one space comp complexity. Can you do that?
45:07:28
Okay. Now let's see that how can we solve this problem using the constant space. For that we are going to do some
45:07:35
few modifications. And what are the modifications we are going to do? Well, first we will have to understand that
45:07:41
what are the items we need for any particular cell. We need the information of number of live neighbors it has.
45:07:48
Okay. But we need this information on terms of like number of live neighbors
45:07:54
in the original state. So now what would happen is that if we are at this
45:07:59
particular position zero this zero would be changed to one and then when we come to this position then we will try to
45:08:05
find that how many number of live neighbors in the original state it had. Then we don't need to consider this
45:08:12
particular value. So we need a way to somehow store its original state and
45:08:17
this can be done pretty easily. How? Basically currently we are dealing with integer values over here. So rather than
45:08:24
using zeros and one, what we are going to do is we can also use minus1 and value number two. And what would this
45:08:31
minus1 and value number two would represent? Well, it would represent is that if say for an example if the
45:08:38
current state is one. Okay, so currently it is alive. Okay, if the current state
45:08:43
is one and somehow it becomes dead then in that case rather than this one would
45:08:51
have been converted to zero. We are decreasing the value but rather than putting this as zero we can actually put
45:08:56
this as minus1. And what would that do is okay so that that means that this minus1 should be dead. This is like we
45:09:03
are using it as a placeholder but this minus1 would also indicate that the original state for this particular cell
45:09:10
was actually one. So when we are counting the live neighbors it originally had in the previous state we
45:09:16
would be able to calculate same way if we are in a position where uh a dead
45:09:21
state comes to life. So dead becomes alive if that happens. In that case from
45:09:27
zero to rather than going to one we would directly go to position number two. And that is also another way that
45:09:35
whenever we identify value number two we would presume that originally that was not live in the previous state whenever
45:09:42
we are calculating the next value. So if we need to do that we need to make some changes to our rules. And what is the
45:09:48
change we are making? The change we are making is that anyhow if the current state is live and if the next state
45:09:55
needs to be dead in that particular case this is where we are going to put minus
45:10:00
one. So because this becomes dead we are going to put this as minus one. For this particular case one if there are two and
45:10:06
three live neighbors this is going to remain one. So we don't need to do any changes over here. For this particular
45:10:11
one if the number of neighbors is greater than three which means that this one would become would die. So this
45:10:16
would also become minus one. And for this particular zero if the number of neighbors is three uh so in that case
45:10:23
this would become alive. So we would change the value to two. So these are few rules we are changing. And now let's
45:10:29
see that how can we make the things work out uh in the in place without using any
45:10:36
additional memory. Okay. So this particular row we are not changing because we are implementing this
45:10:41
particular rule. Now we are at this position number zero. So this zero needs to be uh needs to bring back to alive.
45:10:48
So if if this is coming back to alive rather than making this alive with value number one we are actually going to mark
45:10:54
this as value number two. So this would also indicate that if the value is two then the original state was zero and
45:11:00
this is going to be very helpful. Now we are at this position number one. How many number of live neighbors it has?
45:11:06
Okay. So currently it has 1 2 3 and four. Four live neighbors. Not this one
45:11:12
because the value is two which means that the previous state was actually zero. So we are not considering that. So
45:11:17
since this has four live neighbors so greater than three live neighbors this needs to die. If this die we are going
45:11:23
to use this as minus one. So that is going to be helpful to us in the future. So this becomes minus1 which would
45:11:30
indicate that the original state was actually one and this is going to be helpful. Now we are at this position
45:11:36
number zero. How many number of live neighbors it has? So it currently has 1 2 3 and also four live neighbors. not
45:11:44
three four live neighbors because this one used to this minus one represents
45:11:50
that this used to be originally one. Okay. So this would remain zero. Now again for this particular zero zero how
45:11:57
many number of live neighbors it has. So currently it has okay. So this was originally zero and this was originally
45:12:03
one. So this only had one live neighbor which means this would remain zero. Same goes for this one. This particular zero
45:12:09
has okay one live neighbor and also two live neighbors. So if there are two live neighbors, we don't need to do anything.
45:12:16
And for this particular one, how many number of live neighbors it has? It only has one live neighbor, which was this
45:12:22
value number minus one. So this is going to turn out to value number zero. But rather than turning to value number
45:12:28
zero, we are going to turn it to minus one. And this is going to be the next state. Now once we get this next state,
45:12:35
this is not the answer we need to return because for our game of life, we need to return all the cells in either zero or
45:12:41
one. either they are dead or they are alive nothing more than that. So in that particular case what we can do is if at
45:12:48
any point we identify the value to be uh like positive. So in this case this two
45:12:53
so this needs to be converted to value number one because this indicates that this one is alive and if we find zero or
45:13:00
negative value which means that that one is dead. So in that case we will make
45:13:05
these changes. So these two are going to become zeros and this one is going to become one and this is going to be the
45:13:13
next state and this is the whole solution. See how beautifully we are able to change everything by just simply
45:13:21
making few changes to the input rules. And now if we see time and space complexity in this case the time
45:13:27
complexity is actually going to be bigo of m cross n because that is the grid size we will have to traverse. And if we
45:13:33
see space complexity, the space complexity is going to be big of one because apart from using like few
45:13:38
variables, we are not using any additional space. And this is a very beautiful solution.
45:13:46
Okay. So since this is already a pretty long video, I'm just going to explain you the code and then I would post this
45:13:51
code in the solution. So you would be able to check it out from there. Now if we see, okay, initially we are initializing an array called neighbors
45:13:58
where we are adding the value 0, 1, and minus one. And this is going to help us navigate through neighbors of any
45:14:04
particular cell. At the same time, we are getting the values of the row row length and column length. So this these
45:14:09
are the values of m and n inside our grid. Now first of all we are creating
45:14:15
two for loops one inside the other where this would allow us to iterate over the
45:14:20
given input matrix cell by cell. After that we are originally initializing a value of integer live neighbors because
45:14:27
this is the most important thing we need to consider that how many live neighbors any particular cell has and this is
45:14:33
exactly what we are going to do next. We are going to run two loops but this is going to be a finite number of cases we
45:14:39
need to do. So this is not going to add any additional time complexity to our problem but this is going to allow us to
45:14:46
iterate over our neighbor. We are using this condition. So we do not go out of bounds. And then at any given position
45:14:53
if we find that any particular neighboring cell has value number one then we are going to increment the
45:15:00
number of live neighbors for that particular I and J positions. So this okay so this part gives us the number of
45:15:07
live neighbors. That is pretty awesome. After that now we are going to implement our four rules that we have established.
45:15:14
And for these four rules remember first of all we are going to check that if the
45:15:19
given cell value is if that is dead or alive. If the given cell is alive then we are going to check that whether it
45:15:26
has the number of live neighbors less than two or greater than three. If that is the case then the cell needs to die.
45:15:33
And if the cell dies we are going to change the value from 1 to minus one. And if that is not the case we will
45:15:39
check that if the given cell is actually dead. If that is the case, which means
45:15:44
we are going to check that if the number of live neighbors is exactly three. If that is the case, which means the dead
45:15:50
cell needs to be alive and then we need to change its value from 0 to two. So
45:15:55
basically this particular uh for loop is going to allow us to get all the values
45:16:01
of the board setup with all the cells positions changed from either 0 to 2 or
45:16:08
from 1 to minus1. After getting that, all we need to do is just iterate over the given matrix again and then simply
45:16:16
check that if at any point we identify the value is going to be greater than zero or the value is going to be either
45:16:22
1 or two which means we will need to convert that value back to one or else all the remaining values are going to be
45:16:28
zero. And this is the whole solution. Pretty sweet and efficient both in terms of time complexity and also in terms of
45:16:35
space complexity. So now let's try to run this code. Okay, seems like our solution is working
45:16:40
as expected. Let's submit this code. And our code runs 100% faster than all the other solutions. Uh, which is pretty
45:16:47
great. And I will be posting the solution in the comments. So you you would be able to check it out from there. Also, there is one more place if
45:16:54
you want to check all the coded solutions for many of the lead code problems that I have solved. And this is
45:17:00
the GitHub repository that I have made public that I will be posting this link in the description and also in the
45:17:05
comments. So you can check it out from there. uh let me know uh how what do you think about your this problem and if
45:17:11
there are any problems you want me to solve in the future. Thank you.
45:17:24
Hello friends, we are still not employed by a fang company. So let's not solve lead coding till we get there. Today we are going to do word search lead code
45:17:30
problem. And if we see the number of companies where I want to work at who have already asked this question, there
45:17:36
are companies like Amazon, Twitter, Microsoft, Uber, Bloomberg, Facebook, Tik Tok, Snapchat, Google, Apple,
45:17:44
Samsung, Roblox, Goldman Sachs, Bite Dance and eBay. So these are really
45:17:49
popular companies and this problem is really popular because it has very real life applications. We have all played
45:17:55
games like crosswords and word on our phones and on the newspapers and different kinds of stuff. So that is
45:18:01
where this problem is associated with and we are going to see that how to solve this one. So that's why I'm paying
45:18:07
my utmost attention. I hope you also enjoy the video. So this is a lead code medium problem.
45:18:13
And basically we are given an M cross and grid of characters called board and we are also given a string called word.
45:18:20
Now we need to see that if this word can be created based on whatever the number
45:18:25
of characters we are given on this board and if it uh does we need to return true else we need to return false. Also we
45:18:32
are given a note that the word can be constructed from letters sequentially adjacent cells where adjacent cells are
45:18:39
either horizontally or vertically neighboring and we are also told that same letter cell may not be used more
45:18:45
than once in order to create that word. So let's try to understand this this with an example. Over here we are given
45:18:52
this big board and on this big board we are told that we need to find the word A
45:18:57
B C C E D. So if we see over here on these marked values so this starts with
45:19:04
the word A. The neighboring word is B the neighboring word is C. Again we are told that we can horizontally or
45:19:11
vertically see the words. So uh if we go vertically downwards we see another C
45:19:16
and then we find another E and at the end we find D which is also adjacent to
45:19:22
E which is this letter and this is basically part of this given board. So in this case we can return true. Now
45:19:29
suppose if this word we we if we were not able to construct this word we would not return true and we would return
45:19:35
false. So let's see that what would be the optimal approach to solve this problem. Well, we have actually solved
45:19:40
similar problems like this in the past using DFS and backtracking and this is what we are going to do for this problem
45:19:47
as well. Let me quickly show you how. Okay. So suppose this is the custom example we are given and we need to find
45:19:54
the word spider to see that whether it exists on this given board or not. And
45:19:59
the idea is actually quite simple. What we are going to do is first of all we are going to take the first uh character
45:20:04
inside this word which is s and we are going to iterate over this matrix until we find this first character. The moment
45:20:10
we find the first character from whatever the place is then we will keep on trying to find the next uh letter uh
45:20:17
the next words inside this word h to see if it exist in the neighboring node or
45:20:23
the neighboring cell of uh the board inside this given matrix. And if somehow we are able to reach to the end of this
45:20:29
word, we can we can return true. If we don't reach the end of the word and we actually reach the end of the matrix, we
45:20:35
can return false. So the idea is actually quite simple and uh there are just few tweaks we will have to use in
45:20:40
between. So first we will start iterating over this uh matrix trying to find this word number s. Now uh this is
45:20:48
not s this is not s. Over here we find the first value as s. So because this is
45:20:54
the first value is S. Now we will have to try to see that whether this P exists or not in the neighboring node of this
45:21:00
S. We can clearly see that P exist. Uh so but before doing that what we are
45:21:05
going to do is we are actually going to mark this node as visited. So one way to do is is to use some visited hashet and
45:21:12
store all the values. But that is just causing strain on and to have an extra memory usage. Rather than doing that we
45:21:19
are going to actually modify this input and we are going to mark it something like hash or something which is an
45:21:26
invalid value and it can never be there. So which means at any point we encounter that this value is hash we don't need to
45:21:32
go back to that place. Now we will start iterating over the neighbors of this S.
45:21:38
So neighbors of S can be these three three places. If we try to look at these three places and we are looking for the
45:21:44
alphabet P. So P is present over here. Which means that so far we have found S
45:21:50
and P. Now we will update our value to I and we will try to look for I in this P's neighbor. Also we will go we will
45:21:57
mark this node P as like hash. So we don't come back to this place again. Now
45:22:03
this P has only two neighbors because this neighbor S has already been visited
45:22:08
because its value is hash. So we can't do anything about it. Now we are looking for this letter I and we find the letter
45:22:15
I over here which means again we will mark this as hash. We will update the value of word we are looking for. The
45:22:21
word we are looking for now is D. We'll try to find the neighbors of I. Uh and in the neighbors of I. Okay, we don't
45:22:28
find anything over here. This is not D and this has already been visited which is hash. Which means that there is no
45:22:34
neighbor of I that contains this value D. Which means that now we are we are we
45:22:40
haven't found the word so far and we still have matrix to go to that we haven't visited so far which means that
45:22:46
now we will backtrack from this I to the position we were originally at which
45:22:53
means that from this I we came from P from this to this P we actually came
45:22:58
from S. And now we can say that okay even in this s it does not lead to lead to us to find this word and then we will
45:23:06
again process proceed with our search. So again we will we are trying to find
45:23:11
this letter S again and not the D because we did not find anything in the route which means that now okay this P
45:23:19
is not S this I is not S. This T is not S. So we are good so far. Now at this
45:23:24
position we find the uh letter S which means that okay this S has been found.
45:23:29
Now in the neighbor of this particular cell we will have to find the val the letter P and we are going to mark this S
45:23:37
as hash as to as a way to identify that this has been visited. Now we are what
45:23:44
are the neighbors of S? These four are neighbors of S. And the one value we can
45:23:49
find where the P exists is this one. So again we will repeat the same process. We will mark this as a hash. We'll try
45:23:56
to find the word I. I we will find over here. So again we will mark this as a
45:24:02
hash. And we will try to find D in the neighbor of this I. So we find D over
45:24:07
here. So again we will mark this as hash. We will go update the word we are looking for. And now we will try to
45:24:13
search for E inside this these uh neighbors. And we can find it over here.
45:24:20
Again mark this. and then try to find this R. So R we actually find in the
45:24:25
neighbor of this one and this is the correct R which means that now we are able to reach to the end of this word
45:24:32
list and we can return true in this case saying that okay this actually exist inside this given board and uh we will
45:24:39
be good. So this solution works perfectly fine. Let's see the time and space complexity with this one. So for
45:24:44
the time complexity actually the time complexity is a little bit tricky to find. Why? because the time complexity
45:24:50
is actually big of n which is the number of cells. So for every single cell we will have to iterate at least once. So n
45:24:57
is given but then we will have to repeat the same process for three times to the
45:25:02
length of l in the worst case scenario. Why three times to the length of l because notice that at any single
45:25:09
position suppose we were at the at this position number d and we need to see
45:25:15
that okay whether the next value e exist or not. So we need to check three places
45:25:21
not this one because this of this already has the value hash which means we won't check this one but we in possib
45:25:27
in theory we might have to check at all three places and imagine if all three of them had the value e we might have to
45:25:35
explore the paths on all three of them in order to find the next value r. So
45:25:40
that is why at every single position n we actually have three different options
45:25:46
to see that whether this word exist or not and this l is actually length of the given word. So that is why this is the
45:25:53
time complexity in terms of space complexity we actually need to store the
45:25:58
value inside our space until the time we reach to this entire word. So it would
45:26:03
be big of L where L is the length of the word that is given and this time and
45:26:09
space complexity works perfectly fine and uh I hope this solution makes sense to you. Let me quickly show you that
45:26:16
what would be the coding for this one.
45:26:22
So for this uh word search problem we will actually have to create a backtrack public method that will call itself and
45:26:28
recursively we will try to achieve its answer. So there are some variables that we will need in both the in this boolean
45:26:36
exist method and also in the new backtrack method that we are trying to create. So let me define some variables
45:26:43
uh that are global and that we can use in both the methods and the variables we are going to create is to store the
45:26:49
value of this board and we will also need the row and column size of this given board character array.
45:26:56
Now we have these we will assign values to all these three variables from these given input endpoints.
45:27:05
Once we have this we will have to iterate over this board uh character array. So we are going to assign two for
45:27:12
loops and for both the for loops we are going to have the i and j value iterate up until the point of this rows and
45:27:19
columns and inside this for loop we will call our backtrack method.
45:27:26
Now inside this uh for loop we are going to call our backtrack method and we are going to have backtrack method return a
45:27:32
boolean reply either true or false and uh inside the backtrack method we are
45:27:38
actually going to pass in the values of the current row position current column position word we are trying to find and
45:27:46
the index value we are currently at. So for the index value we would initially start with the position zero and we
45:27:52
would increment it every single time inside our backtrack method. And if at any case this returns true we can simply
45:28:00
return true in this case and somehow if we are able to complete this loop and
45:28:06
get out of it without returning true which means word does not exist. So we can return false.
45:28:12
Once this is done, now we will create our public boolean method called backtrack.
45:28:19
Now first of all we will check that what is the condition where we will need to return true. So if at any point we
45:28:25
identify that the index value is actually greater than or equal to word length which means that we have already
45:28:32
found that uh the current word already exist inside our given character array.
45:28:38
So we can return true in this case. So now we will try to find the terminating conditions and inside the
45:28:45
terminating conditions first of all we will check that whether the row and column position are they going out of bounds or not. If they are going out of
45:28:51
bounds we can return false immediately. If that is not the case we will try to see that the current value we are
45:28:57
looking at inside our board. If that bo that value is not in sync with whatever
45:29:04
the index value of the word we are looking for. If the that is not the case, we can also return false
45:29:09
immediately. So if any of this these conditions are true, we can return false immediately.
45:29:17
None of these conditions are true, which means that the current index value actually matches the value of that row
45:29:22
and column position inside the board. And now we will have to iterate over the neighbors of this current uh row and
45:29:29
column value inside the board. So in order to iterate over the values of the
45:29:35
row and column, we are actually going to have two uh arrays called row direction and column direction. And that will help
45:29:42
us navigate all the neighbors of any particular cell.
45:29:48
Also before moving to the next element, we are going to mark the current row and column position to have a value called
45:29:55
hash. So we avoid checking the same element twice. Okay. Once this is done uh we will also
45:30:02
have a boolean variable called uh return and uh initially we are
45:30:09
going to initialize its volume value to false because basically we are going to call the backtrack function uh for all
45:30:16
the four neighbors of the current cell. So for that we will keep track of this
45:30:22
uh rat variable and we are going to run a loop to
45:30:27
iterate over all the directions and we will add the values of these row
45:30:33
direction and column direction to subsequent row and column positions inside this recursive call to our
45:30:38
backtrack function. We will also update the value of the index because we can determine that we
45:30:45
have already find the word inside the previous index and that's why we are calling the next index where value to be
45:30:52
searched inside the neighbors of any given row and column position
45:30:57
and also at any point if we identify that the answer of this return function is actually or this return variable is
45:31:03
actually true we can break out of that particular element immediately and we don't have to check all the other
45:31:08
neighbors. So we will put that condition as well. Once that is done, uh basically we are
45:31:15
done with the checking part. Now the only thing we need to do is we will have to uh update the value of the row and
45:31:23
column position to whatever the value that was originally there.
45:31:29
And in the end we can simply return whatever the answer we got for this function. This is pretty much it for
45:31:36
both our backtrack method and also our main method. And this should be able to
45:31:41
solve our problem. Let's try to run this code. Okay, seems like our solution is
45:31:46
working. Let's try to submit this code. And our solution works as expected. And
45:31:53
uh I would be posting this in the comments so you can check it out the solution from there.
45:32:08
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. So the question we are going to do today is
45:32:14
called longest increasing path in a matrix. And if we see some of the companies where I want to get a job who have already asked this question, there
45:32:20
are companies like Apple, Door Dash, Google, Facebook, Tik Tok, Nvidia, Amazon, Uber, Microsoft, Snapchat, Bite
45:32:27
Dance and bunch of more. So I'm going to pay my utmost attention. I hope you also find this useful. So this is a lead code
45:32:34
hard problem and also very well-like problem which is a rare combination to find. Uh basically we are given an M
45:32:40
cross an integer matrix and we need to return the length of the longest increasing path in this given matrix.
45:32:47
Now what how do we build this longest increasing path that we need to return the length of? Uh essentially we are
45:32:53
told that from every single cell we can move in four directions left right up or
45:32:58
down and based on that we need to calculate that what is going to be the longest increasing path. We are also
45:33:04
explicitly told that we don't have to care about diagonally moving or values outside the boundary. So let's try to
45:33:10
understand this with an example. Suppose in this case this is the example that we are given. Now our aim is to find the
45:33:16
longest increasing path. Now we know that uh from any single cell how to define an increasing path. Let's say
45:33:23
that we are currently located at the cell number four. Now we have the option to go in four direction up, down, left
45:33:29
and right. Now from this four direction we only need to go to the direction of the cell that is actually increasing
45:33:36
order. Uh so we are we need to maintain this increasing property. So from this
45:33:41
value number four what are the places we can go? We can go to 9 and we can go to eight. We cannot go to six because this
45:33:48
would be a diagonal and we cannot go anywhere outside the boundary. Now in both the cases we have the option that
45:33:54
the values are currently in the increasing order for this 8 and 9 which means both are legitimate scenario but
45:34:00
our aim is to find the longest increasing path. So from 8 do we have any other option to go to that increases
45:34:06
in the path? No. From again from 9 do we have any other option to go to in any
45:34:12
any next cell that increases again? No. So in this case from four the longest
45:34:17
increasing path we can make is going to be two. But this is this the longest inside the given entire matrix. The
45:34:24
answer is no. We need to find the cell that has the longest increasing path. So
45:34:29
if we take one more example let's take an example for this value number one. Again at this location value number one
45:34:35
we have the option to go into four direction. But let's say that for the ease of convenience we decide to go into
45:34:41
the direction of this 1 to2. Currently the in the increasing path length is one. Again from this two we have one
45:34:48
more neighboring cell that is higher than the value that is this value number six. So this time the increasing path
45:34:54
value will increase by one. And again from this six we we can go to one more neighbor that increases in the value and
45:35:01
that is value number one. And originally we started with this value number one and we moved one hop. So basically we
45:35:07
will add one more over here. So essentially we can create a path that looks like this. uh 1 2 6 and 9 and this
45:35:16
would be the longest increasing path in our matrix and the length of this uh
45:35:21
matrix is going to be value number four that is what we need to return in the answer
45:35:26
and the first approach comes to our mind is the brute force approach. The very basic approach that we can take to solve
45:35:32
this problem. Now let's try to understand that what would be the brute force approach in this manner. Well, of
45:35:38
course the answer is quite simple. From every single cell we start iterating in all four directions and from all four
45:35:46
directions we will see that where we can find the increasing path and the moment we find the increasing path we keep on
45:35:52
adding the value to our answer uh variable and we will keep on adding one
45:35:57
over here and same way for our increasing path we will go to its neighbor and again we will keep on
45:36:03
repeating the same process. So let's try to see the solution I'm proposing in action. Okay. So let's say that for the
45:36:09
ease of convenience we start at value number one uh or this value number nine again from 9 what would be the
45:36:16
increasing path we are we are able to make and what is the maximum answer we have find so far these are the two
45:36:21
variables we are going to keep track of so 9 does not have any neighbors that are in the increasing order because 9 is
45:36:29
the biggest value amongst all so in this case we won't be able to find anything let's go to this another nine again same
45:36:35
thing will happen we won't be able to find anything so these two are uh the the values that we took care of. Now we
45:36:42
are at value number four. Since value number four we already calculated that there are only uh two paths we can take.
45:36:48
So currently the uh increasing path maximum we can make is going to be two. So answer currently we have found so far
45:36:54
is value number two that this is the maximum path we are able to make. But let's keep on increasing with next
45:37:01
subsequent values. So currently the values we took care of is going to be the first row. So I'm just going to mark
45:37:06
them as X that we already took care of this. Now we are at this value number six. From six, what are the options we
45:37:12
have? We cannot go here because this is not increasing. This is same. Uh we can go here to 9. So this is good. So from
45:37:19
six, we can again create a path of increasing path of size two and then
45:37:25
that's it. So again our answer will remain same. We also took care of six. Same for same goes for this six. uh this
45:37:31
six we have the option to go to value number nine and we have the option to go to value number eight but that won't
45:37:36
lead to any further results. So again we cannot move anywhere forward. So we also
45:37:41
took care of these five variables. Uh now let's move on to value number eight. Again from this value number eight we do
45:37:49
not actually have any path to go to. So we don't we don't even bother updating any of the variables. Uh now we are at
45:37:56
value number two. And now things will start to get a little bit interesting. So what are the options for the
45:38:01
increasing path we have at value number two. So first increasing path option is over here. So from 2 to six that is
45:38:07
good. Again from six do we have the option to go for the increasing path? And the answer is yes. Uh that is 6 to
45:38:13
9. So in this case from this value number two the maximum increasing path we can achieve is going to be value
45:38:19
number three. So we are going to update our result. And so far the longest increasing path we have found so far is
45:38:24
going to be value number three. So again we are going to result uh we are going to update our answer as well. Uh now we
45:38:30
are at value number one. So what are the options we have so far? Can we go to this? No. Can we go to this six? Yes. So
45:38:38
currently we go to this six. From this six what are the options we have? We can either go to 9 or we can either go to
45:38:43
eight. So let's just first go to eight. Okay. Now we went to the eight. From eight can we go anywhere else? No. So in
45:38:49
this case for this particular path the answer we found is three. But we still
45:38:55
have one more option that from six we can still go to this nine. So even if we go from 6 to 9, we don't have anywhere
45:39:01
else to go. So once again the answer is going to be three as well. Now uh after taking care of both of these path now
45:39:08
let's see let's explore more options. Uh and that option is that from this one we can go to this value number two. Okay.
45:39:15
From this two we still have option to go to value number six. From this six we still have option to go to value number
45:39:21
nine. So in this case we created a path that is 1 to 2 to 6 and then to 9. So in
45:39:27
this case we created a path with a path length of four that is going to be the
45:39:32
maximum path we have found so far. So we are again going to update our values. So this is going to be the current
45:39:39
increasing path we found for the cell number one. And the maximum path we have been able to find is also going to be
45:39:44
four. So we are going to update our answer because we need to enter the most uh the longest increasing path. And now
45:39:51
we still have one more value that we need to go to. So again from this value number one we have the option to go to 1
45:39:57
to 8 and then from 8 we won't be able to go anywhere else. So in this case the maximum path we are able to achieve is
45:40:03
going to be two. Uh after completing or after iterating every single value we found out that the maximum longest
45:40:10
increasing path we can create is going to be value number four. So our brute force approach gave us the appropriate
45:40:16
answer that we were looking for. But what was it the most optimal answer? Well the answer you already know that of
45:40:22
course not. And why? Because there are a few things we can actually make changes to. So first thing we can make change to
45:40:31
is going to be regarding uh that for every single cell we were actually doing
45:40:37
lot of repeated computation. Uh and how we were doing that let me give you a
45:40:42
quick example. So again let's clean this up a bit. Initially when we were
45:40:48
traversing our answer when we reached to this value number six we already knew that from this six there is only one
45:40:54
path we can go and that is going to yield us the higher result and that is from 6 to 9. So the longest increasing
45:41:01
path or the longest path we can make at value number six was going to be two. Now when we came back to this value
45:41:07
number one originally from one what we did was we went from 1 to two from 2 to
45:41:13
6 and 6 to 9 every single place repeating the computation we did we we have already completed and that is a bad
45:41:20
approach. What if we already knew that at value number six the longest we can do is going to be two. Same way this
45:41:26
value number two the longest we can make is going to be value number three. So from based on this information if we are
45:41:33
at value number one and we need to go back to this value number two we can clearly see that from one we already
45:41:42
know that there is an increasing path that leads to two but from two we already know that the maximum amount of
45:41:49
value it can generate in terms of longest increasing path is going to be of value number three. So rather than
45:41:56
doing all of this computation, we could have actually just done from one we
45:42:02
reach to two and see that we already have the computation result for two. So we could have done 1 + 3 and the answer
45:42:07
would have been immediately available available to us as the value four. So this is one of the major significant
45:42:14
improvement we can make. And what this improvement is this is actually we are storing the results that we have already
45:42:21
calculated. So what we are doing is uh one of my favorite things and one of the most beautiful things that is available
45:42:27
in the computer science that is we are actually using dynamic programming in this case. Uh but on top of using
45:42:34
dynamic programming we are also doing something more interesting and that is that we are actually uh rather than
45:42:41
treating this as the matrix or 3x3 matrix we can actually treat this uh as
45:42:48
individual nodes and this individual nodes would have some way of connection with them. How connection because we are
45:42:55
trying to find a path. Now for this path we are actually given the definition that if only from this current cell
45:43:02
let's say the value of current cell is A. If there is a path from A to B where
45:43:08
B is greater than A then only we can connect A to B and consider it for our
45:43:13
path. So rather than treating this as just 2x2 matrix or m cross n matrix, we
45:43:20
can actually consider every single cell in this matrix is equal to node and the
45:43:26
path that we are trying to connect actually as the vertices.
45:43:31
And once we do this uh after seeing these two words immediately in your mind
45:43:37
it's going to click that essentially we are treating this as a graph solution. uh and we are try in the graph we are
45:43:43
trying to find the longest increasing path. We already know how to build a path and that is using the greater than
45:43:51
or less than uh relation between any two cells. So essentially we already have a
45:43:56
directed graph and we already know that this is there won't be any cycles in
45:44:02
this graph because uh let's say that uh how does the cycle occur in a single graph. Let's say we go from 3 to five up
45:44:09
uh in the same position three. Then we can say that there is a cycle. But in this case it is not possible to have a
45:44:15
cycle. Why? Because the relation of this edge is actually based on the property
45:44:22
that three is less than five. That's why there is an edge that exist over here. If three was not less than five, then
45:44:29
there won't be any edge over here. So which means from 5 to 3 there is an edge there is an impossible way to create an
45:44:37
edge. So essentially this is also going to be an asyclic graph and the we
45:44:43
already know that this is a director a cyclic graph uh and in the d ag or
45:44:50
direct a cyclic graph we are trying to find the longest path basically rather than treating it as longest increasing
45:44:57
path we are just trying to find the longest path. So essentially now our life becomes much easier. On top of that
45:45:05
we are already going to use the dynamic programming properties. So we are going to know that how we are going to take
45:45:12
care of every single value. So we are not going to repeat the computations that we have already created. Now let's
45:45:18
see that what would be the solution look like in action. Okay. Okay. So now what we are going to do is we are actually
45:45:25
going to create a dynamic programming uh to m cross n grid. Uh and in this case
45:45:30
we are going to use this to store that every single element how many increasing
45:45:36
path we can make maximum amount of increasing path we can make. So this would be a great help for in terms of
45:45:42
memorization. On top of that for every single node we are treating it as a
45:45:47
graph and uh we are going to build the graph upon them. So we are not actually creating a separate graph. We can
45:45:53
actually use the same matrix for the visual representation. I'm going to make some uh circles and some arrows. But you
45:45:59
would be able to imagine that what we are actually trying to do. So first let's say that we are at value number 9.
45:46:05
So we are at a graph node like 9. From 9 do we have any edges extending out? No.
45:46:12
Because this is the same as 9 and this is less than uh 9. So there is no edges.
45:46:18
Which means the longest path we can make at value number nine is going to be of value number one. Okay, we are we are
45:46:24
good with this result. Now at this second cell 9 again same thing is going to happen that we are going to have a
45:46:29
single cell that is not able to branch out or connect with anything else. So once again the longest path we are going
45:46:35
to make is going to be value number one. Now we are at this value number four. What are the options we have? So let me
45:46:41
just clean this up a bit. And from this value number four we actually have couple of options. We can either grow
45:46:48
from four 4 to 9 or we can go from 4 to 8. So let's say if we decide to go from 4 to 9. Do we need to calculate that
45:46:54
from 9 how many values we can go to? No. Why? Because we already know this result. So from this four let's say if
45:47:01
we go decide to go to 9 we are actually going to create a path like this that uh
45:47:07
uh initially we are going to have a node four and from four we have the option to go to 9 or from this value number four
45:47:14
we have the option to go to value number eight. So currently we have two options from this eight we don't know how many
45:47:19
options we have because we haven't calculated but we we already calculated the result for this value number nine
45:47:25
which means if we decide to go from 4 to 9 we are for sure guaranteed to have an
45:47:31
increasing path of two because from 9 it does not lead anywhere else. So we are
45:47:36
good with this so far. Which means uh and from this four to 8 let's say if we
45:47:42
decide that from four we are going to go to eight. What are the options we have? From 8 we cannot go here or here. So
45:47:49
again from 8 there are no possible nodes that we can calculate which means we are
45:47:54
again going to be able to create a maximum path of two. So in this case rather than doing all of this
45:48:00
computation we can actually create store our answer and we can just put down the value two over here uh that this is the
45:48:08
longest path four can take. Now we are at position number six from six uh what are the options here it has well six as
45:48:16
you can clearly see that six is not able to go over here. it is only able to go over here and this we already calculated
45:48:23
from so that means that from six we only have two options uh and uh that is the
45:48:29
longest path we can make is of value number two again from this six we have two options we can go to this value
45:48:35
number eight or we can go to this value number nine uh in either case the maximum path we are going to make is
45:48:41
going to be of size two reasons you already know from this eight we cannot actually go anywhere else so the longest
45:48:48
path we will be able to make is going to be one. Now from this value number two, we actually have just one option that we
45:48:55
where we can go and that is to go to this value number six. But from this six we already calculated the results and
45:49:01
that is going to be two. So in this case we can clearly write the answer as three. Now from this one we actually
45:49:08
have multiple options to go to. So this I'm going to draw in the answer and you
45:49:13
would be able to understand what I mean. So initially we are located at this value number one. From this one we have
45:49:19
the option to go to value number six. Uh from this one we also have the option to go to value number two. And from this
45:49:25
six we have the option to go to value number eight. And uh we also have the option to go to value number 9. From
45:49:32
this two we have the option to go to value number six. And then six we have the option to go to value number 9. And
45:49:39
currently we are located at this position. So these are the possibilities or these are the options we can have.
45:49:45
Let's assess each path. So in this case if we go from 1 to six uh then from six
45:49:51
we can either go to 8 or we can either go to 9. In either case the answer for this portion is going to be value number
45:49:59
three. But in this case if we decide from 1 to 2, 2 to 6 and 6 to 9, we are
45:50:04
going to get the answer to be of value number four. So in this case four is the maximum answer we can get. But we don't
45:50:10
actually have to do all of this computation. Why? Because we are using dynamic programming. That is the most important concept uh so far. So from
45:50:18
this value number one the moment we see that this is where we can go our mind
45:50:23
should click that if we go if we take this path then what we would do is from
45:50:28
here we would if we take this path then the sum is going to be three. But from here if we take this path then the sum
45:50:34
is going to be four. So obviously we are trying to find the maximum value. So we are going to store the value four rather
45:50:40
than storing the value three and four is here. Now we are again located at this
45:50:45
value number one from this one. Can we go over here? No. Can we go over here? Yes. So what is the maximum path we can
45:50:51
make? We can do one jump like this. And we already know that there is there is only one single entity path we can
45:50:57
choose over here. So maximum value we can get is going to be two. So this is going to be our dynamic programming uh
45:51:05
graph combination matrix combination solution and that is why this is treated as a hard problem. But in my opinion if
45:51:12
you already knew these concepts then it won't be so difficult for you and after watching this video I can guarantee that
45:51:19
this is definitely not going to be hard for you. So we can clearly see that in the end we only need to return the
45:51:27
maximum value that is present inside the dynamic programming graph and that we can return quite easily and this is
45:51:33
going to be the whole solution. Now this is a very beautiful solution. If we see time and space complexity in this case
45:51:39
essentially the time complexity is going to be big of 2 * m cross n. So overall
45:51:45
we can write the time complexity to be big of multiplied by n which is a very good time complexity. And if we see
45:51:51
space complexity well this is little bit uh more expensive because we are using an additional 2x2 or m cross n matrix
45:51:58
over here. So this is also going to be go of multiplied by n. But this is also reasonably acceptable. This is not very
45:52:05
complicated. So in my opinion this is a very good problem to understand three major concepts uh and that is graph uh
45:52:13
dynamic programming and also matrix. So everyone should do this problem at least
45:52:19
once. Now let's go to the coding part that is not so difficult. So basically first of all we are going
45:52:25
to create 2D array uh to store all the directions that we are going to traverse
45:52:30
over. Uh we are also going to have some private integers that we are going to use. Now the first idea is to create or
45:52:37
to find the longest increasing path as an input. We are using the matrix that we are given in the input and we are
45:52:44
simply going to iterate over the given matrix. We are also going to create an a cache or a dynamic programming m cross n
45:52:50
array and we are simply going to have our answer stored initially as as value number zero. Then with using two for
45:52:57
loops we are going to iterate our n cross n array and we are going to check
45:53:03
that whether at any single cell position are we finding the maximum longest
45:53:08
increasing path or not. And for to do that we are actually going to call another helper method called DFX where
45:53:15
in the DFS as an input we are going to provide matrix the current I and J position. So to identify that which cell
45:53:22
we are talking about and the current array that we or the current dynamic programming matrix that we have created
45:53:29
and populated. Now inside our DFS method we are first of all going to check that for any particular value are we have we
45:53:37
already checked uh that particular cell value or not and we are going to initialize the dynamic programming array
45:53:43
as zero. So if the value is not equal to zero then we need to find the value for that and we are now going to iterate in
45:53:51
all four directions from that particular cell then we are going to check that we are going out of bounds or not using
45:53:57
these four conditions. If not then we are only selecting the path where the adjacent values are going to be in the
45:54:04
increasing order. And if that is the case then we are going to update the value of our current cache with whatever
45:54:12
the maximum value we can find for that existing cache or recursively calling
45:54:17
the DFS method again and in the end we are going to add one more value to our cache because we found an additional
45:54:24
path that exist and let's say if we don't find any additional path still the initial value of cache is going to be
45:54:30
zero. So if we increase it by one it is going to be added by one. So let's try to run this code.
45:54:38
Seems like our solution is working as expected. Let's submit this code. And our code runs pretty efficiently
45:54:44
compared to a lot of other solutions. Uh I would be posting this uh code in our GitHub repository. And that link for our
45:54:52
GitHub repository is actually posted in the uh description. So you you would be able to check it out from there. Thank
45:54:57
you.
45:55:12
Now in this topic we are going to study design or system design related problems
45:55:17
that can be asked in either system design problem where you are going to be viewing it from a different lens or they
45:55:23
can be given some input parameters and some specific information. So that becomes a DSA problem. Now these are
45:55:29
some of the most favorite problems especially if you're intermediate to senior level because now you have some
45:55:35
exposure to actual real world scenario on how things work and if an interviewer
45:55:41
wanted to test out that whether you know some basic DSA and also can you think
45:55:46
outside of the box and if you have to make a fullyfledged production ready scalable system how would you do that so
45:55:53
it can operate in both the both manners and I have taken some questions that are
45:55:59
pretty popular. So again they are really good and they have some element of DSA on it because on a system design as a
45:56:07
topic on its whole it can be like a fully separate 100hour long video and there there are like lots and lots of
45:56:14
things to consider. So we are not diving deeper into that just now we are still going to be focused from a point of view
45:56:21
of technical interviews. So without any delay let's get started.
45:56:27
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better at technical interviews. Keeping with
45:56:34
that goal in mind, today we are going to do a very interesting lead code problem called moving average from a data
45:56:39
stream. And if we see some of the popular companies who are already asked this question, there are companies like Spotify, Facebook, Amazon, Google,
45:56:46
Apple, Indeed, Microsoft, Uber and Goldman Sachs. So that's why I'm paying my utmost attention. I hope you also
45:56:53
enjoy the video. This is a lead code easy problem and also a very well-like problem on lead
45:56:59
code. Basically, we are given a stream of integers and we are also given a window size. Now, we need to calculate
45:57:06
the moving average of all the integers inside the sliding window. Which means
45:57:11
we only need to calculate the moving average of the maximum size of the
45:57:16
window size that is given. If we identify more elements than the window size, we will simply kick that element
45:57:22
out. So let's try to understand this with this example. In this example, basically first of all we are given the
45:57:27
moving average value. So moving average currently is three. Which means that there can only be maximum of three
45:57:33
values which we need to do the average of. Now the first value we get is
45:57:38
currently we get the value first value as one. Okay. Currently we only have one value. So what will be the average? So
45:57:44
let me just create a new sum called average over here. And basically the maximum window size is currently three.
45:57:51
Okay. Now we only have since we only have one element basically the average is going to be one because it's like uh
45:57:57
we all know the formula of average that the total sum divided by total size. Okay. So in this case since sum and size
45:58:04
both are one basically the value is going to be one. Now if we see the example the second value is 10. So now
45:58:10
since this this value is 10 and because this value is 10 currently uh it is
45:58:15
still less than the window size we we need. So basically the average now going to be uh 1 + 10 divided by uh 2 because
45:58:24
we have two elements. So basically the average is going to be 5.5. Okay. Now we add one more element. So which is three.
45:58:31
If we add the element three over here. Now this time the new average is going to be 1 + 10 + 3 / 3 which is going to
45:58:41
be 14 / 3. So the value comes up to 4.66. This is going to be the third
45:58:47
average and we need to keep track of every single average. Okay? So we are keeping track of this 1, 5.5 and 4.66
45:58:55
all of them and next element that comes in the next element is five. Now in this
45:59:00
case since the next element is five because if we add five over here we
45:59:06
would have four values inside our window. But the thing is we are explicitly told that our window cannot
45:59:12
have more than three elements which means we will have to kick one element out. Now which element are we going to
45:59:17
kick in kick out? Basically the first value that was entered we will kick this value out and we will add new value over
45:59:24
here. So now we are going to have these three values only without the value number one. So now the new average is
45:59:30
going to be 10 + 3 + 5 / 3. So the answer is going to be 18 divided by 3
45:59:36
which is 6. And these are the four averages we need to return as the answer. The ones that I have highlighted
45:59:43
in white. Okay. So all these four we will return. And this is what the problem is asking us to solve. Now if we
45:59:51
see the solution for this problem is actually quite simple. Okay. Suppose we are told that the maximum window size
45:59:58
can only be three and the values we are given subsequent values are say for an
46:00:03
example 1 2 3 4 5 something like this. These are the five values we are given
46:00:09
and the maximum window size we can have is three. What we will do is basically for the average we are going to have
46:00:15
five values. Now uh first we are only going to have value number one. So currently let's just assume I'll create
46:00:24
a new window over here. Now uh not here. Okay, let me just do it here. Let me
46:00:29
just create a new window over here and one by one we will keep on adding the values over here and whenever we run out
46:00:36
of the space we will kick one value out. So first we will have value number one. Okay. So let's add value number one over
46:00:43
here. So we are adding from this side. So currently the value is one. So the average is definitely going to be one.
46:00:49
Okay. Okay, we are good good up until this point. Now next value is two. Again we add two from this side. So we add one
46:00:55
more value two. So since now the new average is going to be 1 + 2 3 divided by 2. So 1.5. Okay, we are good. Next
46:01:02
value is three. So we can add three because the window size is still three. So if we add value number three. Now
46:01:07
this time the average is going to be uh 3 + 2 5 + 1 6 / 3. So the average is
46:01:13
going to be two. Okay, we are good up until this point as well. Now the value number four comes in. Again remember we
46:01:20
are adding all the values from this side which means we will have to kick the value number one which means we are
46:01:26
kicking out this value and then we are shifting all of these values one step. So let's just quickly do that. So we now
46:01:34
we have since we have already kicked out the value number one and we have the values 2 3 and four and one has been
46:01:40
kicked out. Okay. Now we since 2 + 3 5 + 4 9 9 divided by 3 the average is going
46:01:47
to be three. Okay. And now in the end the we have value number five. So again we will have to kick out this value
46:01:53
number two. So let's just quickly update all the values. So this is going to be 3, four and five. And we are going to
46:01:59
kick out the value number two as well. And now the average is simply going to be four. So this is the moving average
46:02:07
for the window size three. Now if you notice one thing we kept on adding values from this side and whichever the
46:02:15
values were first added were the first values to be kicked out and then we maintained a certain window. So if you
46:02:22
see this is a very similar structure to a Q data structure and this is what
46:02:28
exactly we are using. So and this is the optimal solution of the problem as well. I just showed it to you that basically
46:02:35
we just initialize a que of whatever the window size is is given. So we
46:02:40
initialize the queue of window size three in this case and then all we need to do is keep track of the running sum.
46:02:47
So we will have a variable called sum and depending on the window size we would be able to calculate the average
46:02:53
instantly because we will have the value sum and we will have the value of the average. Now at any given time do we
46:03:00
need to calculate every single average again and again? No. Why no? Because say
46:03:06
for an example at this particular portion like before this five was entered the values we had was 2 3 and
46:03:14
four. And now we know that we need to add value number five. Basically if we are adding value number five and
46:03:21
we are kicking out the value number two. Previously this sum originally was was
46:03:27
9. Now what operation we did? We kick two out. So we will subtract two over
46:03:32
here. Which means now the average is going to be seven. Then we add the value
46:03:38
five over here. Which means that we added five to this seven which means now the sum is going to be 12. So basically
46:03:45
we do not need to calculate the whole sum every single time. We can quickly
46:03:50
calculate the sum depending on the previous values. So which would be very useful to us. So this is the second
46:03:57
thing we need to take care of and using these two portions we can quickly find out that what is the window size because
46:04:03
that is the Q size. So and we know that for to calculate the average we need to add items which is uh the size uh sorry
46:04:11
the sum and the size. Okay. So sum I just showed you how to calculate size we
46:04:16
can find it from the Q size and using the Q this this problem becomes very easy to solve and this is this is why
46:04:22
this is an easy problem to be considered and this would be the optimal solution. If we see time complexity in this case
46:04:28
the time complexity is actually going to be bigo of n where n is the given number of values that we need to iterate over.
46:04:35
If we see space complexity now this is a tricky one. We can consider space complexity to be one because the size of
46:04:43
Q is going to remain constant or we can consider the space complexity to be big of N because we are using an additional
46:04:50
data structure Q where we are storing some portion of the value. So this you can debate with your interviewer but
46:04:56
most likely they are going to agree with size to be of N and this is the whole
46:05:01
solution. So now let's move on to the coding.
46:05:08
So since I'm running short on time basically for this particular code I'm not going to write the whole code but
46:05:14
I'll just explain you the solution and then I'll post the code in the comments so you can check it out from there.
46:05:19
Basically we need two items. First one is the moving average and second one is the method called next. So first for the
46:05:26
moving average method basically we have the public moving average method which gives us the size of our window and this
46:05:33
is the size we are going to use to maintain our que. Now uh initially we
46:05:38
have initialized some variables called size window sum. So this is the sum of current elements inside the given window
46:05:45
and the count because this is a very important we need to make sure that how many elements are there and then we are
46:05:51
initializing a dq. We can also initi in initialize a q over here. It doesn't matter. Both works the same way. And now
46:05:57
let's discuss the implementation of the next value or uh next method. So in the
46:06:02
next method first of all we we increment the value of the count because we are adding a new value. Then for any given q
46:06:10
basically we add the given input value at the back side of the que. So we add a
46:06:16
new value in the que. Now we need to check that whether for the previously
46:06:21
calculated window sum do we need to remove the first element and for that how we are going to check is so in this
46:06:28
case we are initializing a new variable called tail and first we check that if the given particular count if that is
46:06:35
greater than the size which means that our Q has become much bigger than the
46:06:40
given size. uh basically we are going to pull the first element outside the que
46:06:46
and we are going to keep that value assigned to the tail. If that is not the case the tail value is going to remain
46:06:53
zero and we don't need to pull anything from the queue. Then we check that what is the current window sum and the
46:06:59
current window sum we can calculate by doing like window sum plus the value because we are adding the value towards
46:07:05
our window and if the elements became greater than the number of size then we
46:07:11
will have to remove the tail element. So we are subtracting that and then in the end it's pretty easy for us to return
46:07:17
the average and we can simply do it by uh subtract like by dividing the window
46:07:22
sum divided by the size and now over here we are multiplying it by one because this is a double and uh the
46:07:29
window sum is an integer. So this is just for like a integer to double cast thing. Now this is the whole solution
46:07:35
and now let's try to run the code.
46:07:41
Okay, seems like our solution is working as expected. Let's submit this code.
46:07:46
And our code runs decently efficiently compared to lot of other solutions. So this is a very good solution and I would
46:07:52
be posting this in the comments so you can check it out from there. Thank you.
46:08:07
Hello friends, I'm a cloud solutions architect at Microsoft and my aim is to empower every single person to be better
46:08:12
at technical interviews. Keeping with that goal in mind, today we are going to do a very interesting lead code problem called logger rate limiter and this
46:08:20
problem actually has many real life applications that we see in day-to-day use all the time and that is why this
46:08:26
has been a very popular question at many important companies. So if we see some companies that are companies like
46:08:32
Google, Bloomberg, Square, Microsoft, Amazon, Apple, Netflix, Uber and Facebook all have basically asked this
46:08:39
question. So that is why this is a really important question and I'm going to put my atmost attention. I hope you
46:08:45
also enjoy the video. Okay. So this is a lead code easy problem and also decently well-like
46:08:52
problem on lead code. Basically we need to design a logger system for our system
46:08:58
where the property is that it keeps on receiving stream of incoming messages.
46:09:04
Now any single stream of message that comes in it comes in with two items. It
46:09:09
has the some message. So like some something of a string of a message and then it also has the time stamp. Okay.
46:09:16
Now depending on these two values we need to make sure that only unique messages are being printed and during
46:09:24
the duration of 10 seconds there should not be any repeated messages. If there is a repeated message basically we
46:09:30
simply discard it and if the message comes after 10 second we will we are going to print it. Let's try to
46:09:36
understand this with an example. Say for an example this is our system and we keep on getting streams of different
46:09:42
messages. Okay, this could be M1, M2, M3, so on and so forth. There can be like 100 messages that doesn't matter.
46:09:50
We are only concerned about duplicate numbers that come during the window of a 10-second uh time frame. Okay, so this
46:09:58
we don't want. So say for an example, currently this M1, this came in at the
46:10:04
time stamp 1 or 1 second. Okay, currently we are just using it for an example. Now these all could have come
46:10:09
at 1 second, 2 second, doesn't matter. There can be any number of choices as
46:10:14
long as they are separate messages we don't care. But then again during the
46:10:21
again another system again same M1 message came at 7th second as well since
46:10:28
this 1 second message was already printed and over here I'm printing the answer. Okay. So I have printed
46:10:34
currently m1 m2 m3 all of these I have printed so far. Okay m4 as well. Now
46:10:40
again m1 popped up at 7cond but thing is we do not need to print any duplicate
46:10:46
values at 10 second. So since this came in at 7 second we are going to discard
46:10:51
this and then whatever the new messages are we are going to keep track of them and we will consider them to be printed
46:10:57
whether they should be printed or not. Now again the new M1 came same message
46:11:03
okay same M1 message came at let's say 13 seconds. Now since this is this came
46:11:08
at 13 seconds and the before message was printed at 1. Why this was printed at 1?
46:11:14
We are not considering this at the seven because this was never printed. Okay. So
46:11:20
since this was at 13 and the previous one printed was at 1 then we are going
46:11:26
to print this one uh m1 again at the second number 13. And this is the system
46:11:31
or this is the functionality we need to design. I know understanding this problem is more complicated than
46:11:37
actually solving this because the solution for this problem is actually quite simple.
46:11:42
Now let me first quickly show you a very trivial solution and a very complex one.
46:11:47
So the trivial solution is that say for an example we first of all create a que
46:11:53
because we are dealing with messages during a time stamp. Okay. So we are
46:11:58
dealing with two items. Now for this particular queue what we are going to do is depending on the timestamp that comes
46:12:05
in. So we can make this one as like a priority Q or something that deals with
46:12:10
the time frame and only like the first in messages and first out. This is the
46:12:16
methodology we are going to use. Now for this particular Q we already know that
46:12:22
how to keep track of uh the n number of messages for 10 seconds because we this
46:12:28
q is only going to have the value uh it is going to store for the 10-second period. Okay. The moment 10 second
46:12:35
passes we are simply going to pop out the values that was already in the queue and the new values can keep on coming
46:12:42
in. But this 10-second window is important. And during this 10-second window since we need to maintain that
46:12:49
there should not be duplicates. So okay no duplicates are needed. This is also
46:12:55
another thing we need to keep track of. So in order to keep track of 10 seconds we are using Q. But in order to make
46:13:02
sure that there are no duplicates we are going to have a hash set that would be
46:13:07
in sync with this Q. And this is the solution Q plus hashet. So this would be
46:13:14
the hashet we will keep with that would be in sync with this Q. And what we would do is simply say for an example M1
46:13:22
message came in. And since this Q can only have messages for 10 seconds. Okay,
46:13:28
this is the property we already set up. Now let's say M1 message came in. Currently this Q say for an example is
46:13:34
empty or it does not have any entries. So we are adding this value M1 over here. Since M1 has been added at the
46:13:41
same time we will check inside the hash set as well that whether the entry for M1 already exists or not. Currently M1
46:13:49
there is no entry for M1 exist. So since there is no entry for M1 exist we are going to add a new value to our hash set
46:13:55
as well that is called M1. Okay. Now we added M1 over here and say for an example this M1 came in at 1 second. Now
46:14:03
currently M1 is located inside our priority Q at 1 second. We know that after 10 second this M1 needs to be
46:14:10
kicked out and at the same time uh say for an example after now again 7 seconds
46:14:17
has passed. So after 7 seconds again M1 came. Now since M_sub_1 repeatly came
46:14:24
now this Q we can we do not want to check inside the Q that whether M1 exist
46:14:29
or not but at the same time we can check inside the hash set and currently M1
46:14:35
already exist inside the hash set and since hashet and Q are in sync with each
46:14:41
other we can say for sure that since M1 is present inside the hash set it has to
46:14:47
be somewhere present inside the Q which means we are going to discard this one and we don't do anything with this one.
46:14:54
Now let's again go back to the new scenario and the new scenario is that now enough time has passed and now we
46:15:00
are at a value number 13 and again we get the message M1. Okay. So again we
46:15:06
got the message M1 and the time stamp is 13. But the thing is the current Q we
46:15:12
had we were only storing values for 10 seconds. The moment 10 seconds pass, we would start popping out the values from
46:15:18
the priority Q. Which means this M1 must have been kicked out. And we are also
46:15:24
going to keep track of one more thing. The moment we kick out any element from
46:15:29
our Q, at the same time we are going to kick it out from our hash set as well. So this M1 at the end of the 10 second,
46:15:37
it is it got also kicked out from the hash set as well. There can be some other entries, we don't care. Okay, M1
46:15:43
has been kicked out and at the same time now the second is 13. Of course, for the
46:15:48
Q we will we will see that we will ask the hashet that hey does M1 already
46:15:54
exist and since M1 does not exist so we will add an entry M1 over here and we will also let M1 inside our Q and we
46:16:01
will print the M1 and this is one way to set up our logger limiter system.
46:16:07
Remember what we did is we use the combination of Q
46:16:12
and hash set to solve this problem. The thing is your
46:16:19
mind must go through that why are we making things so complicated when both
46:16:25
of these things can be achieved in a single data structure and that single data structure is
46:16:31
actually hashmap and what we could have done is we could have simply created a hashmap. Now inside this particular
46:16:38
hashmap we are going to have two values and for these two values the first value we are going to keep track of is the key
46:16:45
and then the next one is its subsequent value. Okay, it's a key value pair kind of a data structure. Now this can have
46:16:51
multiple entries. Now as a key we are actually going to keep the value of the
46:16:57
message. So whatever the message we receive because remember in our logger
46:17:02
system we are receiving bunch of different messages and there are only very few messages that we need to print.
46:17:09
So as the whatever the message values M1, M2, M3 and this M1 can be anything.
46:17:15
This M1 can be that hey I got a job in fang. Okay, that doesn't matter but that we are going to keep track of as a key
46:17:22
and whatever the time stamp is, we are going to keep that timestamp as its value and this is going to make our
46:17:28
lives much more easier. How? Say for an example, currently hashmap does not have any values and then m1 comes in at 1
46:17:35
second. Currently the time stamp is one. Okay. So now as a key we are going to store the value of M1 and as its
46:17:42
subsequent value currently because the entry does not exist we are we are creating a new entry and its subsequent
46:17:48
value is going to be the time stamp. So current time stamp is going to be one. Okay now we have this entry inside our
46:17:53
hashmap. Now the next thing we are going to do is again at the same time we are
46:17:59
going to this can have this can receive multiple entries at once. So there can be another entry for M_sub_2, M3, this
46:18:05
can be three, this can be two, there can be any number of values. Okay. And whatever the values we add inside our
46:18:11
hashmap, we are also going to print them as well, which is the necessary thing that we need to do. But again, if we
46:18:18
receive the value M1 at 7, then we come at this M1. Okay, since M1 entry already
46:18:25
exist. Okay, now if it exist, then we need to compare the T timestamps. So
46:18:30
currently this time stamp is 1 and this time stamp is 7. So since the difference is less than 10. So if the difference is
46:18:37
less than 10 actually we do not need to print this one. So we are simply going to discard this message. And then again
46:18:44
new M1 comes at let's say 11 second and since 11 second the difference is more
46:18:50
than 10 seconds or so in this case we are again going to print out this M1
46:18:56
message and the moment we print out the M1 message we will update its timestamp to 11 and this will allow us to check
46:19:04
for future M1 messages. This is the whole approach of this problem. And if
46:19:09
we see the time and space complexity using the hashmap method because hashmap method is the most optimal method. So in
46:19:16
that case the time complexity is actually going to be bigo of uh we can consider it to be big of n because that
46:19:23
depends on the number of messages being received. But uh in theory the checking portion can be done because for hashmap
46:19:30
uh we we know that the insertion takes big of one time and also the searching takes big of one time. So these
46:19:37
operations are pretty quick. The only time that takes is the time for input to
46:19:42
come in. So that is why this big of n but in from our applications point of view it is going to be big of one. And
46:19:49
if you explain this to your interviewer he's going to fall in love with you. And then the space complexity. So the space
46:19:55
complexity is actually going to be big of n for sure because we are using a additional data structure hashmap to
46:20:01
store all the values and this is a very good time in space complexity to implement such a primitive and important
46:20:08
method because this has been used by all the companies inside the entire world. So you just did something amazing. So
46:20:15
put yourself pat on your back and now let's move on to the coding.
46:20:22
Okay. Okay, since I'm running short on time, I'm actually going to show you the solution and then I'm going to paste the
46:20:28
solution in the comments so you can check it out from there. Okay, so let's move on with the explanation. First of
46:20:33
all, we create a new public logger method where we are initializing our hashmap because that is the most important thing in the world. And then
46:20:40
we are actually implementing our should I print this message or not method. Now in this case, we are receiving two items
46:20:47
in the input. First item is the time stamp and second item is the message. First of all, we check that our hash set
46:20:54
contains the message as the key or not. If it does not contain, basically we are
46:21:00
definitely going to print this message. So, we can print that and at the same time we are going to add the entry
46:21:06
inside our hashmap saying that what the message was and what its time stamp was. So, this is pretty easy to understand.
46:21:14
Second thing is that say for an example if this does not work which means that
46:21:20
the message already contains. So then we will have to check that what is the old time stamp and that we can simply get by
46:21:26
getting the value from our hashmap. And once we have that we are simply going to check that whether the difference
46:21:32
between the current time stamp and the old time stamp that we have already saved inside our hashmap. If that
46:21:38
difference is greater than or equal to 10 then we are simply going to print
46:21:43
that message and we are also going to return true. If it is not less than 10 and if the time not enough time has
46:21:50
passed simply we are going to say that no we should not print this message and we are going to return false. Notice
46:21:55
that in this case we are not updating the entry inside our hashmap because the previous 10 seconds hasn't passed. And
46:22:02
this is the solution. This is a very simple and easy to understand solution. Now let's try to run the code. Okay,
46:22:09
seems like our solution is working as expected. Let's submit this code.
46:22:14
And our code runs decently efficiently in terms of time complexity and pretty efficiently in terms of space complexity. So again, I will be posting
46:22:22
this in the comments so you can check it out from there. Thank you.
46:22:36
Hello friends, hope you are having a fantastic day today. So in this video we are going to solve a very popular lead
46:22:41
code premium problem called design tic tactoe. So without any delay let's get started. We wants to design a
46:22:48
tic-tac-toe game that is played between two players on an n cross n grid. So
46:22:53
typically we play tic-tac-toe between a 3x3 grid but in this case we are just given that we need to create an n cross
46:22:59
n grid but needless to say even if we have to do it on this grid the logic is
46:23:04
going to remain same and we are going to try to solve it in the optimized manner. Now we are given following the rules but
46:23:11
we all know what the rules are that a move is guaranteed to be valid which means every single move is going to
46:23:17
happen on a block that is empty. Second thing is that once a winning condition is reached no more moves are allowed.
46:23:25
This is the critical portion of designing this problem that is we at every single moment we need to make sure
46:23:32
that whether a winning condition has been established or not and we all know what winning condition looks like. If
46:23:37
any of the player is able to make any such row or column or diagonal fashion
46:23:42
in three sequ sequential values then that player is deemed as winner. uh no
46:23:49
matter whatever the case might be. So let's try to see that what is going to be the most simplest approach that we
46:23:56
can take or the brute force approach to check if at any given position any
46:24:01
single player has reached the winning condition or not. Well the answer is quite simple. Let's assume that any
46:24:06
single player makes a move. So in this case since the move is located at a nondiagonal square we only need to check
46:24:13
that whether this uh happens like all three zeros or whether these happens as
46:24:18
all three zeros. If this is the case we can simply deem this as winning condition and we can we can stop the
46:24:25
game from there there saying that this player has won. If that is not the case then we can continue the game. So if we
46:24:32
have to do this well uh this operation would take big of n time and we will
46:24:37
have to repeat this n operation n times which means the brute force approach would yield big of n² time complexity
46:24:44
and this is just like the most logical thing if we have to do it in most primitive manner. Now let's try to see
46:24:52
that what are the improvements we can make on this brute force approach and for that we will have to understand that
46:24:58
how does winning condition work. So we are given three different options.
46:25:03
Number one option is that any single player is able to complete either three rows. That is one option for the winning
46:25:10
condition. Second one is any single player is able to complete the blocks in three columns. That is the second
46:25:16
portion of the condition. And third condition is that we complete three diagonals. So uh is there a way to make
46:25:24
this solution faster using these three items for every single move that is
46:25:29
being made and we are trying to target to have better time complexity than big of n square and the answer is quite
46:25:36
simple that yes we are able to do that but for that we will actually have to keep track that at any given position
46:25:43
any single move is made uh how many corresponding rows with same uh same
46:25:50
symbol is currently present. That is number one thing we need to check. Second thing, how many number of
46:25:56
corresponding columns have been filled? That is the second thing we have to check. And third thing, whether it is
46:26:01
placed on a diagonal or not. So for that we will have to use some indexes. Which
46:26:07
means now we have a way to identify any single box that how it is represented
46:26:14
based on its row and column value and we can find that particular cell. So what
46:26:19
are the winning conditions? Number one winning condition is three rows. Number two is three columns and number three is
46:26:24
three diagonals. So first let's assume that how can we keep track of three
46:26:29
consecutive rows are present for any single player. Well, for that what we
46:26:35
can do is we can simply create an array with three sections which denotes that
46:26:42
at every single row position where the value is currently placed. And whenever
46:26:48
any single value is being placed, we simply update the value by one for that particular player. And let me try to
46:26:56
explain what I mean. So let's assume that currently we have created a an an
46:27:02
array like this for any single player and we know that at every single
46:27:07
position we are able to identify that box based on the current row and column position. So let's assume that this is
46:27:14
currently our rows array and let me clean this up a bit so it would make things more clear and currently we are
46:27:20
only checking for three row condition. So let's assume that for this one we
46:27:25
currently have 0 1 and 2 as the values corresponding. Let's assume that currently player makes a move that is X.
46:27:31
So now we can define that this move has been currently made at row position zero
46:27:38
and column position zero. Currently we are only keeping track of the rows. Okay. So we are going to say that at row
46:27:43
position number zero there has been one entry that has been made for uh this
46:27:50
particular x character or the player with x symbol. Next let's assume that
46:27:55
this player makes an some random move and then this player makes this move again. Once again we can say that at row
46:28:03
position zero another x has been made. So we will go to our rows arrow and we
46:28:09
will say that at this row's zeroth position there has been one more move
46:28:14
that has been added. So whatever value is we are going to add it by one value. So currently we can mark this as two.
46:28:21
Let's assume that this player makes some random move and once again at the zero row we add one more x which means now
46:28:29
after adding this we will check the row position that is once again zero. So we will try to add it once again and we
46:28:34
realize that this position actually had value number three at one of the locations or one of the index locations
46:28:41
at row. The moment we identify that we can say that this player with X character has actually won the game and
46:28:47
we can stop the game over here because winning condition has been established. This is the scenario in order to
46:28:53
identify that at any given in uh entry point whether a row has been created or
46:28:59
not. Now let's try to understand the second winning condition that is three columns. Once again the logic is going
46:29:05
to remain the same and let's try to redo this all of these operations and once
46:29:11
again now we are going to move in the column direction. Okay. So let's assume that currently one player makes a move
46:29:17
like X. Now this time we are tracking the value zero. Okay. So let's assume that our second player makes the column
46:29:24
uh zero row over here. So currently this zeroth position is located at row 0 and
46:29:30
column 1. So currently for even for our column we are going to have one more
46:29:36
array and once again it is going to have value 0 1 and two. So at position number one currently all of these values are
46:29:42
going to be zero. But at position number one we identify that one character has been made. So we will mark it by value
46:29:48
number one. Once again let's assume that this player makes a move here and this player makes a move here. So once again
46:29:54
at column position number one one we are we have made one more move. So we are
46:29:59
going to add this by two. Let's assume that this player makes a move here and then this player once again makes a move
46:30:04
here. So in this case once again we find that three items has been added at the same position inside the row and that's
46:30:11
why we are marking it as three. So we can also say that a winning condition has been established. So these are the
46:30:16
two scenarios for rows and columns. Now let's try to take care of the third scenario or third third winning
46:30:22
condition on how we are going to keep track of that and that is to keep track of the diagonals. So let's mark the
46:30:30
values 012 and once again 012 and we will try to mark for the diagonals. Now
46:30:36
what are the squares being covered by diagonals? So these are one set of squares and these are second set of
46:30:43
squares. Now in order to identify that whether a value has been placed on a diagonal or not, it is very simple. The
46:30:50
moment we identify that both row and column value are same, we can just make
46:30:55
sure we can just add one more entry that on the diagonal position one value has been added. But the question is we
46:31:02
actually have two diagonals and second diagonal is this one. So for this one how do we identify if any single value
46:31:09
is being added at these two these one of these three positions how do we mark as
46:31:14
this we can call it as anti-diagonal. So we already established that for diagonal
46:31:20
if the row value equal to column value. If that is the case we can mark that one
46:31:25
character has been added for that subsequent uh diagonal. But for anti-diagonal how do we keep track of
46:31:32
that? So for that let's assume that these are the squares we are talking about. So let's see the position of this
46:31:38
square. So currently the row position of this square uh sorry the column position
46:31:44
of this square is equal to two and row position of this square is equal to zero. Same way in this case the row
46:31:52
position is equal to two and once again in this case the column position is equal to zero. So in both the squares if
46:31:59
you do the sum of row plus column you would always find the answer to be n minus one and in this case n is equal to
46:32:07
3 because we currently have n by n grid or 3x3 grid. So the moment we identify
46:32:13
that this is row plus column is actually fulfilling the condition of n minus one
46:32:20
or in this case because this is a 3x3 grid if row plus column is equal to two
46:32:25
then we can for sure say that that particular uh item has to be on a
46:32:30
diagonal and or sorry has to be on an anti-dagonal and for that we can also
46:32:37
consider this square as well because this is also row one and column 1. If we do sum of this, this falls to uh this is
46:32:46
two and this is zero. So for this particular one, the once again the sum is two and once again for this one the
46:32:52
row position is two and column position is zero. So once again the sum is two and no other square is going to fulfill
46:32:58
that condition. Let's try to check our theory. Let's assume that we talk about this square. So currently this square is
46:33:04
located at row position two and column position one. So 2 + 1 is actually going to be three not two. So for diagonal we
46:33:13
already know if row and column are same then it's a diagonal. We can mark it. If
46:33:19
for row and column is equal to n minus one then it's an anti-diagonal and then
46:33:24
we now let's see that how do we check for the winning condition in this scenario. So now the logic is actually
46:33:30
quite simple. All we need to do is at every given moment we need to keep track of row and column position. But now we
46:33:38
don't need to check for the whole thing regarding uh creating separate arrays because there can there are only two
46:33:45
diagonals possible uh normal diagonal and anti-dagonal. So at any given moment if I enter a value on a diagonal it has
46:33:52
to be added for that particular diagonal. So let's assume let's start restart our game. So once again
46:33:58
currently I add one value x over here. So currently the row and column position is 0 0 which means I will have to add
46:34:04
one value to the diagonal. So currently diagonal initial value is going to be zero and anti-dagonal initial value is
46:34:10
going to be zero. But because I added one value over here I will have to do add one value to the diagonal. Okay. Now
46:34:17
let's add a zero some rand at some random place. So I add a zero over here. Once again again for the zero we are
46:34:23
also going to keep track of the same thing. Now let's add one more value on x. Now this x is currently located at
46:34:30
column position one and row position one which means row is equal to column which means in the diagonal we need to add
46:34:36
one. So we can add value one over here. But notice that this is also fulfilling
46:34:42
the condition for anti-dagonal as well because 1 + 1 is equal to 2. So once again we are also going to add one more
46:34:49
value to the anti-dagonal. Now let's assume that for some reason we decide to add one value over here. Okay, zero is
46:34:56
here and then one we add one more value over here. So this is two and this is zero. So in this case we only update the
46:35:02
anti-dagonal and not the diagonal. So once again antidagonal is going to be two. And now for some reason let's try
46:35:08
to add one more value of x. Let's add it on the diagonal. So now this is two and
46:35:14
this is two. So this is diagonal. So even on diagonal we identify value to be three or to be n. So in this case we can
46:35:21
consider that a winning condition has been established. Now let's try to reapply all of this logic that we just
46:35:27
discussed for both the players side by side and then we will try to find some solution. So now we have our uh array
46:35:37
or we have our image. So let's try to put it over here. Okay, let's try to give the index value 012 and once again
46:35:44
012. And now let's create one set of instructions for player X and one set of
46:35:51
instructions for player O. We are going to have initially our row array. So we
46:35:57
are going to store three values inside the row. Once again for column we are going to store three values inside the
46:36:03
column. Once again for diagonal we are going to have just a normal zero. And for anti-dagonal we are going to have a
46:36:10
normal zero. Same thing going to happen for row.
46:36:22
Okay, cool. So now we have all of our answers and now uh let's add first value
46:36:29
x over here. So this is 0 0. So on the row position 0 we are going to mark one
46:36:34
value on the column position 0 we are going to mark one value. Now row is equal to column which means we are also
46:36:40
going to add one value to the diagonal and antidagonal is going to remain the same. Now once again let's repeat the
46:36:47
same exercise for zero as well. Now zero is currently placed on row zero which means on the row we are going to add
46:36:53
value one and column one. So on column one we are going to add value one. Uh this is not on diagonal or antidagonal.
46:36:59
So we don't care. Next let's let's add x one more over here. So this is added on
46:37:04
row two. So on the row sorry column two. So on column two we are going to add value one and row 0 we are going to add
46:37:10
value one more. So row 0 already had one value we are going to add it over here. So let's add value this becomes two. And
46:37:17
now this is 2 + 0. So this satisfies the condition for anti-dagonal. So once
46:37:23
again we are going to mark anti-dagonal as one as well. Now let's add one more zero over here. Okay. So now zero is
46:37:30
currently placed on a diagonal and also anti-dagonal. So we are going to add one one on both of these locations. Plus
46:37:37
currently zero is placed on column number one. So column number one already had one. So we are going to mark it as two. And this is row one. So row one uh
46:37:46
does not have any value. So we are going to mark this as one. Okay. Now let's try to put one more x over here. Currently
46:37:52
this x is placed on uh this is uh row one and column 0. So row one is one,
46:37:59
column 0 is going to be two. Okay. Okay. And this is not a diagonal or antid-dagonal. Now let's put one more
46:38:05
zero over here. So this is row two and uh column one. So on the row two, we are
46:38:11
going to add one value over here. And in the column two or or in the column one,
46:38:17
we are going to add one value three. The moment we identify three, we don't need to do any further calculation because a
46:38:23
winning condition has been reached. This zero has one and we can simply return that zero is the winner and this is the
46:38:28
winning condition. And this game can keep on going on and on and at
46:38:34
eventually we we would either find a draw or a winning condition. But we would be completing this whole solution
46:38:41
in big go of end time only nothing else. And you can notice that this is a much
46:38:47
better time complexity compared to our brute force approach which is awesome. Uh if we see space complexity well space
46:38:54
complexity is also going to be big of n. Why? because we are enabling the these
46:38:59
row and column arrays and they are directly dependent on the number of inputs. So this is the whole solution. I
46:39:05
know I repeated bunch of things many times but the purpose was to explain you in the most simplest manner. And now
46:39:11
let's see quickly see the coding solution. Unfortunately for this one I won't be able to show you that how does
46:39:17
code runs because I currently don't have lead code premium subscription because I ended my subscription and never renewed
46:39:23
it. Uh so I will show you the code and hopefully we can end this video.
46:39:31
So this is going to be the coding solution for our designing tic tactoe. So first we have our class tic tactoe
46:39:37
where we have the array for rows and array for columns. We also have an integer for diagonal and anti-dagonal
46:39:43
and we simply have an integer for the size of the array. This is going to be our n cross n grid. Now let's initialize
46:39:49
our data structure where we are simply providing the value of n. based on this value of n, we are also initializing the
46:39:56
two arrays that we want for rows and columns. Okay. Now we are doing
46:40:01
something slightly different. So we have a method called move and remember at
46:40:06
every single move we have to identify that whether a move whether the game has
46:40:11
ended or some player has won or not. Now the thing is for both of the players we
46:40:16
are given the values as integer and we are marking that for player with value
46:40:21
number zero is marked as one and player with value number x is marked as minus1
46:40:28
or you can do vice versa. Now the question is if we use minus1 over here how would we do the sum of two values
46:40:34
and for that we are actually using math do.absolute function. So no matter what we are always going to be doing the sum
46:40:41
based on the absolute values. So it is always going to come up as positive integer values. So nothing no issues.
46:40:47
Now the idea is very simple. For every single player's move depending on the row and column position we are going to
46:40:53
update the rows and columns array based on the player value. And in this case the player value has been either one or
46:41:00
minus one. And in either case because we are going to be doing absolute value. So we should be able to find it if that is
46:41:06
equivalent to size or not. So we check for the rows and columns. Next, we also update the diagonal value. For that, we
46:41:13
simply have to check if row is equal to column. If that is the case, we simply update the value of the diagonal. Next,
46:41:19
we have to check for the anti-dagonal as well. For that, we check row plus column. And we have the condition that
46:41:25
if the size is uh if that is equal to size minus one. In that case, we also update the value at the antidonagonal.
46:41:31
And then we have a very simple condition that at any given moment we identify that whether the current row position or
46:41:38
current column position in the rows or columns array is equal to the size or the current diagonal position is equal
46:41:44
to size or current anti-dagonal is also equal to size. If any of this position happens we simply return the player
46:41:50
saying that this player has won. If that is not the case and if no one wins uh then we can simply return zero. So this
46:41:57
is a very simple code and once again I will be posting this code in our GitHub repository. The link is in the
46:42:02
description so you can check it out from there. Thank you.
46:42:15
Hello friends. So today we are going to do an awesome lead code problem that has been asked in bunch of different IT companies. So without any delay let's
46:42:21
get started. So the problem is insert delete get random we go of one and if we want to
46:42:28
understand the problem statement basically we need to implement a randomize set class where we need to
46:42:34
implement these three method that is first one is insert second one is delete and third one is get random and we need
46:42:39
to make sure that we implement these methods in big of one time. Now you can see that this is a late code medium
46:42:45
problem and also a very well-like problem. But in my opinion this should have been an easy problem. Also if you
46:42:51
want you can read this whole description. Uh if not let me just give you an explanation that what this problem is asking us to do. Uh basically
46:42:58
we need to create some sort of data structure where we can keep track of three items. First one is add, second
46:43:04
one is remove and third one is get random method. Okay. So let's try to
46:43:10
understand each of the method uh one by one. Now for these two methods we don't need to return any values. We just need
46:43:16
to return true or false because we need to return a boolean value and this would be defined based on the values present
46:43:23
inside the existing set or not. So let's assume that currently this is an empty set and we are being asked that okay
46:43:29
just add value number five. So if we have to add value number five we can add value number five and because five was
46:43:35
already not present inside the existing set we need to return true in this case. Next we can we can we might be asked to
46:43:42
return add value number seven. So once again for seven we will add it and return true. Once again we might being
46:43:48
asked to add value number nine. So once again we will repeat the same process and the answer is also going to be true.
46:43:53
But now let's say for an example once again we are being asked to add value number five once again. But because five
46:43:59
is already present in this case we can't add the value to our existing set. But
46:44:05
we can simply say that for this five because it was already present, we did not add it inside the set, we need to
46:44:11
return false. So this is the logic for the add method. Second logic for the remove method is also very similar that
46:44:17
let's assume that for this example we let's add one more value 11. Okay. And
46:44:23
now for remove we are being asked to remove value number nine. So first we need to check that whether 9 is present
46:44:29
inside our data structure or not. Yeah. So 9 is present. If 9 is present, we need to remove 9. So let's get rid of 9.
46:44:36
And currently we only have three values 5, 7, and 11. And because 9 was present
46:44:41
and we removed it, once again we need to return true for this one. Once again, let's assume that we are being asked to
46:44:47
remove value number 17. Now 17 is not present inside our existing data set. So
46:44:52
in this case, we will return false because we did not remove any values from our data set. Okay. And for the get
46:44:59
random method, this is just very simple. Whatever the values are currently present inside our uh set or data, we
46:45:07
simply need to pick any random value. So if we are being asked to get random, we can return value number seven. Next time
46:45:14
we might return value number 11. Next time we might return seven again. Next time we might return five. Once again we
46:45:20
might return five. Any number of values it is going to be randomly picked and we have no control over it. Now for all of
46:45:26
these three cases simply we are just uh implementing the same method and also
46:45:32
the logic is going to be that we need to complete all of this in big go one time. Okay. Now the thing is for this get
46:45:38
random actually it is very beneficial for us to use any existing method that
46:45:44
is present for any single language like C, Java or Python. All of these language
46:45:49
they have their own way where they actually store or where you can actually
46:45:54
pick a randomized value from the existing set. So this is very beneficial
46:46:00
to us. But there are few problems in our cases and we need to do things slightly
46:46:06
bit differently in order to achieve the solution. Now first let's try to take
46:46:11
this problem one by one iteratively. And the moment you understood that we need to solve this problem in big go of one
46:46:17
time. Uh you must have understood that we need to do one or two things. We can
46:46:22
either do use hashmap or hash set in order to solve this problem. So if we
46:46:28
have to solve this problem actually if we only needed to do like add and remove
46:46:33
method we should be able to complete this using hash set or hashmap. Both of this would fruition the same result and
46:46:40
we would be able to complete this problem in big goof one time using any of the hashing data structure. So let's
46:46:46
try to see that in example. Let's assume that we initial initiate a hash set and now currently we try to add the values.
46:46:54
So let's assume that we add value number five. Okay. So five was not present inside the hash set. We can check this in big off one time because it was not
46:47:01
present. We add value number five to hashet and we can simply return true. Once again we need to add value number
46:47:07
six. So once again we will repeat the same process add six and return true. Same way we need to add value number
46:47:13
seven. So once again we will return add seven and return true. Okay this works in big of one time add method no issues.
46:47:20
This is a very simple thing. Once again if we have to implement the same logic for the remove method. Let's say that we
46:47:26
need to remove value number six. So we can simply return true and say that okay six has been removed and uh that's it.
46:47:32
Yeah we can say that because six was present we removed it from the hash set. So it is no longer there and we return
46:47:37
true. Once again we need to remove value number eight. We can check in bigo of one time that whether 8 is present
46:47:43
inside our hashet or not. Because it is not present we need to return false in this case. So both of these logic works
46:47:51
exactly fine. No issues with this. But when we need to do get random method, we
46:47:57
cannot implement get random method in this scenario because typically get
46:48:02
random for that we need to say that okay uh give me if if I use like predefined
46:48:09
method of get random from any single language that method typically works like that uh if there are values between
46:48:15
1 to 100 give me any random value and it can return any value between like 7 or
46:48:20
51 or 55 something like But the thing is in our case we only need to find the random values between
46:48:27
value number five and value number seven. Now one logical method comes to our ways that we take count of all the
46:48:34
values put them in some sort of list and then in the list we only keep the values
46:48:40
that are already over here. So we we are simply going to create a list of size two where we are going to have values
46:48:47
five and seven and then we can say that give me a random value amongst between
46:48:53
zero and one uh 0 and one uh index values and based on
46:49:00
the index value. So let's say for the first random we get index value one. So we return value number seven. Uh let me
46:49:06
broaden up the horizon. So let's assume that there are few more values. Okay 9 and 11. So between 0 to 4 I need to
46:49:14
return some values. Okay. So in the 0 to 4 I need to return some values. And now in the first uh 0 to 3 basically four
46:49:22
values. So in the first time it says that the value is two. So if value is two we need to find the value at index
46:49:29
location number two that is value number nine. So we can return nine. Uh next time if with the value is three once we
46:49:35
can return value number 11. So so on and so forth. Now the thing is for get random. In order to use get random we
46:49:42
need some sort of indexed data structure where we store all the remaining values
46:49:48
and then we select a random index value and whichever value is located on that
46:49:54
index location we need to return that value. So we already know that we
46:49:59
already took care of this uh add and remove method using the hash set. Okay.
46:50:05
But the thing is in order for us to implement this get random method, we need to keep track of a list that
46:50:13
contains all the values that are currently present inside our hashet. And we need to know that at what index
46:50:20
location, which value is present because when we try to add a value, we need to add it at any particular index location
46:50:27
or we need to keep track of that index location. Why? Because when we have to remove that value, we can remove it from
46:50:34
the hashing data structure. But we also need to remove it from our array list. And if we don't know the index, if we
46:50:40
have to search one by one, then this becomes big of n operation. So this is the complexity. But once you know that
46:50:47
you will have to use uh two data structure, this becomes very easy and very simple to do. So let's try to solve
46:50:54
this problem and we will try to go through the add, remove and get random methods. Now you all know that how does
46:51:00
get random work. Once we have this list with all the data structure and list only contains the data that is currently
46:51:07
present inside our uh hashing data structure. It can be hash set or hashmap
46:51:12
anyone. Uh then it is very easy to implement the get random method. Okay. So this we already know but tricky part
46:51:19
is managing this list with this hashing function at the same time. So in this approach hash set would not be a good
46:51:26
choice. Actually we will have to use a hashmap in this problem. So let's try to solve the same thing using hashmap
46:51:32
because we need to keep track of the index location. This is the important part. So now once again let's assume
46:51:39
that this is currently our hashmap. In the hashmap we know it's a key value based data structure. So as part of the
46:51:46
key we are actually going to store the value or the incoming item that comes in
46:51:52
with our method add. Okay. Or add or remove these comes in with an integer
46:51:58
value. So whichever the integer value that it comes in with this is going to be stored in the key portion of our
46:52:04
hashmap. And as part of its value, we are also going to have a subsequent array list. And inside this array list,
46:52:12
it is also going to be going to have index values. So let me mark some index values over here. 0 1 2 3. Okay. and as
46:52:19
part of its value we are going to store the index numbers so that we can do add and remove operations quite easily. Now
46:52:26
let me let's say that now let's see the logic for the add operation. Let's assume that I need to add value number
46:52:32
one. Okay. So I can add value number one over here because one was not present. First I will check whether one is
46:52:38
present or not. Because one was not present I add value number one inside our hashmap. Okay. All of this
46:52:44
operations happens in big of one time. At the same time I add one in the very
46:52:50
last position of the array list that we have created. Now currently this array list is empty. So very last position is
46:52:56
also going to be uh index value number zero. So I'm going to store one over here and whatever the index value is
46:53:03
that is going to be the size of the array list and that index value I'm going to store as the value for our
46:53:09
hashmap. So this is going to be value number zero. Same way I'm going if I need to add value number two once again
46:53:14
the logic is going to be same two two and because this index location is one so I'm going to store one as the value
46:53:20
let's add value number five so five and index value is two and let's add value number seven so seven index value is
46:53:27
three and uh this is our array list so far okay and for all of these operations
46:53:33
I'm returning true because these values were not present now let's say that I do one more operation add value number
46:53:39
seven once again so in this case because seven is already present which I can check in bigo of one time. So because of
46:53:46
that I can simply return false saying that seven is already present. So I cannot add seven inside our uh data data
46:53:52
set that we have stored. Now let's go back to the remove function. For the remove function the logic is actually
46:53:59
quite simple but we need to do some additional steps. Why? because we need
46:54:05
to make sure that this uh list only contain the data that is that are
46:54:10
currently present inside the hash and any data that is out of order we need to
46:54:16
fix the order because we might need to remove some element from the middle as well. So what is going to be the logic?
46:54:22
Let's assume that we are being asked to remove value number five. So what we can do is first go to the value number five.
46:54:27
We know that five is present which means we will have to remove this. So the answer is going to be true. That is for
46:54:33
sure. But what is going to be the logic for removal? First we will check that okay for five where it is stored inside
46:54:39
our array list. So it is stored at the index location too. So this value we
46:54:44
will have to remove. But if we remove this value then we might end up in a position where the values would be 1 2
46:54:52
then this is going to be a null value and then uh the last one is going to be
46:54:58
value number seven. Okay. So now the problem is uh that the value number null
46:55:04
is no longer there and in this case u if we have to
46:55:11
implement our get random method. If we randomly select value number two then we
46:55:16
might end up returning null which means we will only need to keep the valid values no longer the null values. So for
46:55:22
that what we are going to do is let's assume that that we get rid of this one
46:55:28
and then this is a null value. We need we realize that we need to remove value number five from this position two. So
46:55:34
one simple logic is that we are going to swap value number five with whatever the last element is inside our hash inside
46:55:42
our array list. So let me remove this one. So we are now we are going to have
46:55:47
a scenario where this is value number seven this is value number five and then we can simply get rid of the last
46:55:52
element inside the array list. So we will not have five over here and we will also not have five value number five
46:55:59
over here and we are simply going to have value number 1 2 and 7 inside our array list. And uh we are also going to
46:56:06
have 1 2 and 7 inside our hashmap which means our add and remove function will
46:56:12
work exactly fine. And when we get to a level of get random, we can simply
46:56:17
select the random value of amongst any one of these three index values. So
46:56:23
currently the index values are going to be give me a random value between 0, 1 and two uh index values and I can it can
46:56:30
randomly pick any values and this can work for even if we have 100 values the
46:56:35
same logic is going to be there. So this is the approach. Now the time complexity
46:56:41
obviously for add remove it works in big off one time because we are using hashmap uh and for the get random
46:56:48
because we are using the pre-built method that operates in big off one time and we are only searching for the index
46:56:54
value and find fetching a value from the index value of the data structure works in big off one time then also it is the
46:57:01
same thing. So this problem this is the whole solution of this problem and it's a very interesting problem once you
46:57:07
understand the trick. Okay. So now let's see that what is going to be the coding logic for this problem.
46:57:13
Okay. So now let's see the code for insert delete get random. So first we are going to initialize our hashmap and
46:57:20
we are also going to initialize an array list. We are also going to initialize a v variable called rand to store the
46:57:26
random values and we are going to initialize our public randomize set class. Now first thing we need to
46:57:33
implement is the insert method. So for that we need to implement a boolean method insert where we are inserting a
46:57:39
value. The first thing we are going to do is check whether this value is part of the key of our hashmap or not. If it
46:57:46
is part of the key we can simply return the false. If it is not part of the key we need to add the value to our hashmap.
46:57:53
For that we are adding the value as the key. And the size of current array list
46:57:58
is going to be the index value because we are always adding the value to the very end of the list. And we can also
46:58:04
add the value to the existing list as well. And we can simply return true. Now let's see the logic for the remove
46:58:10
operation. So first we check that whether the value is present inside the key or not. If it is present, if it is
46:58:16
not present, we can simply return false because there is nothing for us to remove. If it is not present and if the
46:58:22
value is present then we need to first get the index value uh for that
46:58:27
particular position and we need to get the last element inside the existing list because we need to swap the values.
46:58:34
Okay. Then we are going to swap the elements inside the existing set that that is about to be removed and we are
46:58:41
going to update the value inside our hashmap. Plus we are going to simply remove the last element inside the array
46:58:47
list and also inside the hashmap. And in the end we are going to return true that we return the values. And then last
46:58:54
method is the get random method where we are going to simply run the get random
46:58:59
method on inside our existing list. And in order to find the next randomized item, we are simply going to look for
46:59:06
the uh all the available index values of our list. And this is the whole logic.
46:59:12
So now let's try to run the code. Okay, seems like our solution is working
46:59:17
as expected. Let's submit this code. And our code runs much faster than most
46:59:23
of the other solutions. So that is pretty good. And uh this is the whole solution.
46:59:39
Hello friends, hope you are having a fantastic day today. So now we are going to do a very popular lead code problem
46:59:44
called LRU cache and this is a very well-like problem and it is a lead code medium problem. Now this problem can be
46:59:51
asked in two manners. This is a very popular system design cons constraint as well. It's very simple for a system
46:59:57
design but still it is there and also uh it is a lead code problem so it can also be asked in your technical interview. So
47:00:03
I ask you to put higher attention to this problem because it can be asked in two different types of interviews. Now
47:00:09
let's understand the problem statement. Basically we need to create a data structure that follows the constraint of
47:00:14
a least recently used cache. So first let's understand that what are going to be the constraint for the least recently
47:00:20
used cache. The simple thing is purpose of cache is to store some values. Let's assume that currently we have this cache
47:00:27
and we can store three values inside the cache. So the idea is that first I add value number one then I add value number
47:00:33
two and then I add value number three. Now because value number one was the very first value that I entered or it is
47:00:41
the least recently used item in the cache because relatively number two and
47:00:46
number three have been used after being after number one was being used. So number one is the least recently being
47:00:52
used value. So if I have to add value number four inside the cache, I need to
47:00:57
kick out one and I need to add four over here. But in this scenario now the least
47:01:03
recently used item is going to be value number two. And if next element is five, I need to enter then I need to kick out
47:01:10
two and add value number five. But currently now this three is the least
47:01:15
recently used. But say for an example for some reason I ask this cache that hey get me this value number three. In
47:01:22
this case now this three is no longer the least recently used value. Now the
47:01:27
least recently used value is going to be this value number four. So in case if I have to enter value number six in this
47:01:34
case. Now again I'm going to kick out value number four and add value number six over here. This is the constraint of
47:01:41
least recently used cache and this is what we need to implement. But now let's go back to our problem statement and
47:01:47
understand what exactly being asked us to do. So number one thing is we need to create a class LRU LRU cache class where
47:01:55
we need to implement few methods. Number one method is a capacity method. So the capacity method defines that this is
47:02:01
going to be the size of cache. So in this case currently our capacity is three and this is what we come up with.
47:02:07
Okay. Next one is that we need to create a method that gets any particular
47:02:13
element from the key uh from our existing cache. Now the thing is the value we are storing inside the cache is
47:02:20
actually a key value pair uh kind of the thing. So in the input we would be given
47:02:25
values like 1 one. So in this case uh the value we need to store is key value
47:02:31
pair that is 1 one. This is the whole node where one is defined by the key and its subsequent value is value number
47:02:37
one. Okay. Now uh in order for us to put the value now if we have to add a new
47:02:44
value inside our cache then we are given some more constraint. Number one constraint is that we need to update the
47:02:51
value of the key if the key already exist. Okay. So that is number one constraint. Number two constraint is
47:02:56
that if the key does not exist then we need to add the whole key value pair inside the inside our existing cache.
47:03:03
And for some reason if we move out of the capacity then we need to evict or we
47:03:09
need to kick out the least recently used key. So the same thing that we just saw in the example. Okay. So now let's try
47:03:16
to understand this whole scenario with like a slightly broader case and we will
47:03:21
try to understand that what are the things we need and what are the constraints we have and how can we
47:03:27
actually start implementing these methods. Now for all of you I must know that the moment you heard that we are
47:03:33
using key value pair the number one thing that comes to your mind is that we are actually going to use hashmap and
47:03:38
you are exactly correct in order to store all the values inside the cache we are actually going to use the hashmap.
47:03:45
Now the thing is in the in the hashmap the typical structure is that we have a key and we have associated value. Now in
47:03:52
this case the node we are trying to store the node is actually structured as a key value pair in itself and this is
47:04:00
going to be the value and the key is going to be the same key that we are being given inside the node that we are
47:04:05
going to use. But one different thing we are going to do is that instead of storing let's assume that currently the
47:04:11
the value of this node is that key is one and value number is five. If this is the value we need to store, we are going
47:04:18
we are not going to store it like this that number one as the key and value as number five. No, this would be correct
47:04:23
but we will not do that. Instead, what we would do is we will see that what is the pointer location of this node and we
47:04:32
are going to store the pointer location that points to this particular element and it would be the same thing because
47:04:38
we are using the hashmap. So access is always going to be big of one. We can always find this value in be of one
47:04:44
time. But this is going to be greatly helpful for us in order to maintain the order in which the elements came in.
47:04:52
This is the most important part because we are not only storing the values inside the hashmap and kicking the
47:04:57
values out of the hashmap. We also need to keep track of that what was the least recently used item. Which means at the
47:05:04
same time we will also have to keep track of that which was the most recently used item because of the get
47:05:10
operation. You understand my point that what I'm trying to say because remember we need to implement three methods.
47:05:16
Number one method is a capacity. Now capacity is really easy to make sure because that is the that is going to be
47:05:22
the size of our hashmap that we are going to implement. So we will never be able to exceed our capacity. That is
47:05:29
number one that is has been taken care of. Second method is the put method. Okay. Put method is also relatively easy
47:05:35
that I just explained that we as a key we are going to store the key as a pointer we are going to store the node
47:05:41
that we are going to point. Next method is the get method. This is also very easy because we know that in the get we
47:05:49
are being asked that hey uh this is the key and fetch me the whole value. Now inside the hashmap it is really easy to
47:05:55
fetch out values. We can do that operation in big of one time. Let's assume that currently we have a value like two and its subsequent pointer that
47:06:03
points to the value of two and five in the node. If we are being asked to fetch this value, we can fetch it very quickly
47:06:09
in big of one time. But the problem is when we have to for this put operation
47:06:15
when we run out of the capacity then it in that scenario we will have to do an
47:06:20
eviction. Now for this eviction we need to keep track of that what was the least
47:06:26
recently used element that we that we came up with and in this case first instinct is to use a simple Q because
47:06:33
let's assume that for a second we don't have this get operation okay let's assume for a simple second now what
47:06:40
would happen is currently we have our hashmap now inside the hashmap we need to store the values of key value pair
47:06:46
okay and what we are going to do is let's assume that the current capacity is three Okay. So let me add three
47:06:52
blocks. Same way the current capacity of the Q is also going to be three. Now number one thing is first value we are
47:06:58
trying to enter is 1 one. So let's assume that I'm entering value 1 one over here. Same way the very first entry
47:07:03
I'm going to enter inside the Q is going to be 1 because of the key. Second value is 22. Once again second value is two.
47:07:10
Next value is 3 three. Once again the value is three. Now let's assume that there is value number four I'm trying to
47:07:15
insert. What value should I? It's very simple. the very first value that entered inside the queue has to be the
47:07:22
first value that gets kicked out of the queue. So this is very simple to implement but the problem is that
47:07:29
currently this sequence is fine but the moment I apply the logic of get in now
47:07:35
in this scenario let's assume that I decide to get value number two okay let me add this value number four before
47:07:41
okay so let me go ahead and quickly do that uh okay I added value number four
47:07:47
over here I also got rid of one and I adjusted the flow of two and three okay
47:07:52
so now adjusted the flow of two and three and four and now I have already added the value number four. Now the
47:07:58
thing is I apply get operation. Currently in this scenario the least
47:08:03
recently used element is value number two. That is very simple to understand. But now if I do get two immediately two
47:08:10
becomes actually the most recently used element because I just access two. So
47:08:16
now what would be the new flow of the que is that it's going to be 2 4 and
47:08:22
three. And now suddenly three becomes the least recently used character. And in this case if I have to kick one value
47:08:29
out I can also kick that out. Basically if I want to add value number five in this case now I need to kick value
47:08:35
number three out. Now the question is you must be thinking that hey even with the Q we can actually implement the same
47:08:41
thing. What we will do is whenever we are being asked to run a get operation, all we need to do is we first need to
47:08:47
find the value that is currently present inside the existing que move it to the very first element of the queue and
47:08:54
shift all the other nodes one step forward and then also this logic would work but that would be a suboptimal
47:09:01
approach. Why? Because hashmap is going to run in bigo of one time. No issues
47:09:06
with that. Q typically it is going to run in big of one time because we are simply popping elements out from the be
47:09:13
from behind the scenes. But when we have to do the get operation we need to
47:09:18
iterate over the entire queue in order to find the position of that element. And that operation takes big of end
47:09:24
time. And if we see the problem statement we are very explicitly being told that the functions get and put must
47:09:32
run in on an average big of one time complexity. So we need to take care of that scenario. So now let's just break
47:09:39
down the same problem and try to come up with the thinking that what are the things we need, what are the things we
47:09:45
have and what how can we make the solution better. This is the approach you should be thinking in your actual
47:09:51
interviews as well and that is why I created this whole 10-minut preamble of the whole things that we are now going
47:09:58
to come up with the optimal solution. So in this case once again I we already mentioned few things that we are using
47:10:05
hashmap in order to store the values. Now you will understand that why instead of using hashmap to store just the
47:10:12
values why am I storing the pointer of that particular value. Now it will come to your senses. Okay. What I'm
47:10:19
suggesting is that currently remember we need to keep track of two items. Number one item is what is the least recently
47:10:25
used item. Number two item is the moment we use the get operation. We also need to keep track of what is the most
47:10:31
recently used item. And there is going to be all of these bunch of different
47:10:37
element that fall between each other. But basically the moment we are
47:10:42
accessing any particular element that becomes most recently used element. The moment we want to kick out any element
47:10:48
we kick it out from the least recently used element. Which means we need a data structure where we can actually work on
47:10:55
both sides of the queue to either enter the value or remove the value. And we
47:11:01
need to do it in fast and efficient manner. And for that the very simple thing is one of the most basic data
47:11:07
structure that is a link list. But this is not a simple link list. We are actually going to use a doubly link
47:11:13
list. And how this doubly link list is going to help us to do solve all of this uh issues. Let's think about it. So now
47:11:21
let's understand that suppose currently this is our hashmap where we are storing all the values. Let's assume that this
47:11:27
is our double link list. Okay. And currently for our hashmap once again the capacity is three. Now why why are we
47:11:35
using pointer instead of actually using the value that will come to your mind very quickly. So number let me just add
47:11:41
few values. Okay, number one, number two, and number three. These are the three values. And let's assume that for
47:11:46
these three values, I'm marking as pointer one, pointer two, and pointer three as the three nodes that contain
47:11:52
all the all the information. Now, once again, I'm marking these three nodes over here. Pointer one, pointer two, and
47:11:58
pointer three. Okay. And currently inside our doublink list as well because
47:12:04
we added values sequentially in the same sequence, we are going to have Okay. So
47:12:09
this is our least recently used item and this is our most recently used item. Okay. Now the very first item we have in
47:12:16
the least recently used is going to be pointer one or the value one or the node one. Okay. You can think of it all of
47:12:22
these things. So basically value one and one. Same way second is going to be P2 basically value number two and two and
47:12:29
third one is going to be pointer three that is going to be three and three. Now the thing is where this pointer would
47:12:35
come into useful is when we have to change the positions because same logic
47:12:41
will come to your mind that hey in the Q why we were not using Q because in order to find any particular element we had to
47:12:47
jump through all of these places and that was causing big off end time. But in this case we have the additional
47:12:53
benefit that because we have the hashmap based on any particular key location we
47:12:59
can directly find that what is where is that particular value is located inside
47:13:04
the existing cube and all we are concerned about is to storing least recently used and most recently used
47:13:10
values. So now we are going to start manipulating these values. So let me just clean this up a bit and now we are
47:13:17
going to start working our magic. Now let's assume that currently we need to
47:13:22
add value number four in this case. Okay. So we are going to add value number four over here once again. Now
47:13:28
the logic is quite simple. We are simp because least recently used value we already know that that is P1. We are
47:13:33
simply going to get rid of it. But now what we need to do is we simply need to say that whatever the value that is
47:13:40
because we removed the least recently used value which means we removed the head of the existing link list. So the
47:13:46
moment we remove the head of the existing link list automatically the second value becomes the least recently used value. So now we have P2 that is
47:13:54
least recently used currently. Next value is going to be P3 and then we are going to have value number P4 as the
47:14:00
most recently used value. So let me update those values. So P 3 and P4.
47:14:06
Okay. Currently we have these values associated and subsequently we have pointers that point to those correct
47:14:13
values. Now let's assume that for some reason we decide to access value number
47:14:18
three. Okay, we create another operation that is get operation. Get three. Now
47:14:24
the moment I do get three operation suddenly now even though three is in the middle. What I will in order to do the
47:14:32
get three operation first I'll do that whether key number three exists inside the hashmap or not. Yes is it exist. If
47:14:37
it exists all I need to do is I need to fetch the value of the three. So I can simply return that. But at the same time
47:14:44
I can go to this pointer location and I can say that hey whatever your pointer location is now you need to jump to the
47:14:51
head of the uh or sorry to the tail of the link list because currently now you are the most recently used value and
47:14:58
that can happen in bigo of one time because it's a doubly link list. So we
47:15:03
are just going to use the same logic. And now in this case P4 becomes our
47:15:08
second or like second least recently used value and P3 becomes most recently
47:15:13
used value and we are able to find this value because we are using pointer. So we are avoiding the scenario where we
47:15:19
have to iterate over every single value inside the link list and saving up on the time. Okay. Now for the same
47:15:26
scenario let's assume that instead of uh this now we are trying to add value number uh five. Okay. Okay. So if I want
47:15:32
to add value number five, I need to kick out least recently used value. I already know least recently used value is P2.
47:15:39
And in the P2 because I'm storing the whole node, it contains the value as 2 and two. So all I need to do is that
47:15:47
whatever the head position has the node, I just need to go to that key position.
47:15:52
And the moment I go to the key position, I simply delete or remove that key. So
47:15:58
now I'll get rid of this two. Okay. I'll also get rid of this two over here. Now
47:16:04
I my least recently used is automatically going to adjust that is going to be P4 and P3. And now there is
47:16:12
going to be P5 as the most recently used because I can easily manage that. And in this scenario now once again I need to
47:16:18
enter the value five and P5 over here. And that's it. This is the whole logic
47:16:25
of least recently used test case scenario. And uh you can add as many
47:16:31
nodes as you want. The logic will remain same. And now let's try to understand time and space complexity. Time
47:16:36
complexity pretty simple to calculate. We are using Okay. So let's assume for capacity it doesn't matter because it is
47:16:43
like uh we are just allocating some value. So this does not take part in the
47:16:48
time and space complexity scenario. Now let's assume for the get operation. So what were what are we are doing for the
47:16:55
get operation? If we want to get any particular value get three let's assume we are going to check that whether this
47:17:00
key exists inside the hashmap or not. Yes it exists. Now we can easily fetch the value from the pointer. There is no
47:17:07
issue with that. But at the same time we will have to mark three as the most recently used value and that can also be
47:17:13
done in big of one time and this hashmap can also operate in big of one time. So get operation now works in big of one
47:17:19
time. Awesome. Now let's take care of the put scenario. Once again for the put scenario we will also have to repeat the
47:17:25
same thing. Basically uh let's assume that now we have this value number six we need to add we realize that the
47:17:31
capacity is full. So because capacity is full we are going to go to the hashmap
47:17:36
first. Take whatever the head position is. Find what is the key associated with that because it stores key and value
47:17:42
both. And this key contains the value number four. So go to value number four. Kick value number four out. Add value
47:17:49
number six over here. And that's it. You solved the problem. And now this operation also happens in big of one
47:17:54
time. So this is the whole approach. Now let me quickly go over the code. Now
47:18:00
let's look at the code for our problem LRU cache. Uh so first thing we are going to do is we are going to create a
47:18:05
static class node where we are going to store the definition of the node that contains the values key and value. On
47:18:12
top of it we are going to keep track of the previous node and the next node for any particular node. And this aligns
47:18:18
with our doubly linkless concept. We also have a simple constructor to store the value of key and value that comes in
47:18:24
as the put method. Now we have some variables that we need to define. So first variable is the capacity. Next one
47:18:31
is a hashmap. Now inside the hashmap as a key we are going to store the integer value of the node. But as its subsequent
47:18:38
value we are actually storing the pointer of the node and we are pointing it to the element that we needs to put
47:18:44
in that. This comes along as we understood during the explanation. And then we have two dummy nodes that are
47:18:50
head and tail where head is going to keep track of the most recently used and tail is going to keep track of the least
47:18:57
recently used element and then we can simply manipulate those values. Next thing is uh for this is the method in
47:19:04
order to instantiate the capacity. So it is a very simple method. All we are doing is just creating a hashmap of the
47:19:10
same size. on top of it if we have to let's understand the logic for the get
47:19:16
method in which we are given the key as an input. So first thing we are going to check is whether this key exists in the
47:19:22
hash inside the hashmap or not. This we can do it in big of one time. If it doesn't exist we can simply return minus
47:19:28
one. If it do exist we can simply return the node value that is that is perfectly
47:19:33
fine. But before that we need to create or we need to put it as the most
47:19:39
recently used value. So we need what we are going to do is we are going to instantiate a temporary node that is
47:19:45
going to be associated with the given key and for that we are now we are going to remove that from our doubly link list
47:19:53
and we are going to put its position as the at the head value and both remove and insert at head values I have created
47:20:00
helper method for those. So this is the remove method and this is the insert at the head method. These are just very
47:20:06
basic uh pointer manipulations inside our existing link list. Now going back
47:20:11
to our uh get method. Now in this scenario and in the end once this uh
47:20:17
node has been mentioned as the most recently used node then we simply return the nodes value. So that fulfills our
47:20:23
get method. Next let's understand the logic for the put method that is slightly more complicated. We are given
47:20:29
the two input values for the node that we need to put in. Now first thing we are going to do is we are going to check that whether this existing key already
47:20:37
exist and if it does we simply need to update the node associated with that. So if it exist all we need to do is just
47:20:44
assign a temporary node whatever the value of the new node is assign that to the existing value for the for our
47:20:50
existing hashmap key and then we need to remove that node pointer and insert it
47:20:56
at the head because now this becomes the most recently used head used value. If
47:21:01
that is not the case and we need to enter the new value all by itself. So first we are going to check that whether
47:21:07
we are running out of capacity or not. If we are running out of the capacity we are simply going to remove the last
47:21:13
element that exist at the tail. So that we can simply do it in big go of one
47:21:18
time because we can already always find that what is the value associated or at the least recently used using our dou
47:21:25
link list and then we can simply remove that value and then we can simply add a
47:21:30
new in either case now we simply need to add a new node inside our existing hashmap and after adding this new node
47:21:38
we need to add this new node at the head because now this becomes the most
47:21:43
recently used value. So I know that this code looks simp like little bit
47:21:48
complicated but overall the simple logic remains the same. Now let's try to run this code. Okay, seems like our solution
47:21:55
is working as expected. Let's submit this code.
47:22:00
And our code runs pretty fast compared to lot of other solutions in terms of time complexity and also great in terms
47:22:07
of space complexity. So once again, I will be posting this code inside the uh
47:22:12
GitHub repository that we have and you can check it out from there. Let me know in the comments what do you think about this video. Do you think is there
47:22:19
anything else I could have done to make it better? I'm always open for the feedback. So thank you so much for that.
47:22:24
Until then, take care.
47:22:38
So finally we are at the last topic that is bit manipulation or binary related
47:22:44
data structure and algorithm problems. Now I'm going to be very honest with you. You can skip this topic completely
47:22:50
if you want to because there the likelihood of you being asked these questions is very low. But that does not
47:22:57
mean that someone might not ask. And uh the problem that this topic solves is
47:23:03
actually the fundamentals of computer science and somewhat electrical and uh
47:23:08
EC engineering and communication. So it's like multip it goes across multiple
47:23:14
spectrum of computer science related engineering. Uh also we learn deeper
47:23:20
into like how basic electronics work. So different gates end gate or gate nand
47:23:26
gate all the different gates how do they work in terms of introduction all you need to understand is what is the
47:23:32
different truth table for each of those basic gates so I'll be displaying that on the screen right now you can take a
47:23:39
screenshot and just keep it a copy for yourself it's very simple to understand nothing more complicated on top of it we
47:23:46
are going to be solving the most asked and most popular bit manipulation questions even Though this topic is not
47:23:54
very popular. So if you just solve these seven problems, you would be done with this topic. That's for sure. Now I
47:24:01
apologize for the video quality because this was recorded when I was just learning how to record stuff. So they
47:24:08
are not extremely great audio and things like that. So I apologize in advance.
47:24:13
But again the core concept is still uh very much uh viable and helpful to a lot
47:24:21
of people. And I know we are almost done to the finish line. So I hope you have the patience to complete this.
47:24:30
So the lead code problem we are going to solve now is called single number. We can see that this one is a lead code
47:24:36
easy problem and also one of the most like problems on lead code. Basically we are given a non-MPT array called nums.
47:24:43
Now every single element in this array appears twice except for this one ele
47:24:49
one element and we need to find that single element that is only present just once. Now the important thing is we need
47:24:56
to be able to find the solution in linear runtime. So we go of n runtime complexity and using constant extra
47:25:03
space. So using big go of one extra space. Now let's try to first understand couple of examples. Suppose we are given
47:25:10
an input array like this. And then we can see that one appears twice and two appears only once. So we need to find
47:25:15
the single number. So we can return two as the answer. Same way over here if there are more entries still we can see
47:25:20
that two appears twice, one appear twice, three appear twice and four appear twice. Seven only appear once. So
47:25:26
we need to return seven as the answer. So basically this is the problem statement. Now let's approach this
47:25:32
problem in multiple ways. The brute force approach is going to be quite straightforward. So brute force approach
47:25:37
is going to be quite straightforward. we first take a look at the number and then iterate over entire array to find that
47:25:43
whether another copy of this number exist or not and we can keep on repeating the same process over and over. So basically this is an
47:25:50
inefficient approach and this would yield big of n square time complexity in the worst case scenario. Uh next
47:25:55
approach is a slightly simpler approach. We can basically sort the given input array. We can find that then we can just
47:26:02
iterate once and find the value that is only repeated just once. So this approach would be better than the brute
47:26:09
force but this would still run in big of log n login time complexity. So this is still not valid for us. Next approach is
47:26:15
that we can actually use a hashmap to solve this problem. Hashmap or hash set and where we can just simply iterate
47:26:22
over this given input and try to keep on adding all the entries inside the hashmap. We can keep track of the
47:26:29
frequency occurrence and in the end we would find that the frequency for four is only one but that is also still going
47:26:34
to run in big of end time but the space complexity is al also going to be big of so that is also not acceptable. So that
47:26:41
brings us to the last solution we have and now honestly you are not expected to
47:26:48
come up with this solution unless you are like a complete geek or a complete nerd but let me talk about the solution.
47:26:55
Basically we are going to use something called X or gate in between any two numbers. Now you know that this is a bit
47:27:03
manipulation technique and basically we have gates like end gate or gate uh X or
47:27:09
gate and things like that. So XR is a very popular way whenever you are
47:27:14
dealing with multiple entries that cancel out each other and how it works is that this is the truth table for the
47:27:21
X or gate. So let's say that we are given x and y as two separate numbers. So if both are basically zero then we
47:27:29
simply return uh zero as the answer. If both are one then also we return zero as
47:27:34
the answer. So we only return the remaining answer if both values are not
47:27:40
same. So if one is zero and one is one. So then in that case we basically return the appropriate value. Now this xor
47:27:47
logic applies to all the numbers as well. If we do 4x or with four then also
47:27:52
the answer is going to be zero because both values are same. There is also a logic that if we do four then do an x or
47:27:59
with five then do an x or with four then once again these four are going to cancel out each other and we are going
47:28:05
to end up with a result called five and this you can try to understand based on
47:28:11
the x uh x or y truth table for numbers
47:28:16
greater than four. So basically I I'm not going to write down the whole solution but you can trust me on this
47:28:22
that this solution works as expected and uh if you if we have let's say that 10
47:28:28
different entries let's say that a then once again xr of a then once again xr of
47:28:34
x then once again xr of x then once again xr of b plus xr of b and then
47:28:42
lastly if we have plus xr of c in this case all of this are going going to
47:28:47
cancel out each other and only we are going to be left with value C and this is exactly what we are going to do in
47:28:53
this problem that suppose you given our nums array the values are 1 2 3 and then
47:28:58
1 2 3 and then value is four. So basically we would have a result value
47:29:04
that is continuously going to store the values of the xr to its previous value
47:29:09
and uh so in the result value first we are going to do 1 x or 2 same way then
47:29:15
we are going to do that plus x or 3 and if we continues to do that eventually
47:29:20
the repeated values are going to cancel out each other and we would only be left with the only number that is not
47:29:26
repeated. So in this case in the result we would find the value four as the answer and basically this is the whole
47:29:33
solution. If we see time and space complexity in this case the time complexity is going to be bigo of n and
47:29:38
the space complexity is going to be bigo of one because we are not using any additional space apart from using couple
47:29:43
of variables. So this is relatively easy and simple approach to solve this problem and u once again this is a
47:29:51
pretty popular bit manipulation problem. So now let's quickly see the coding solution. So the coding solution is
47:29:57
actually the smallest that I have done so far. Uh basically we just initialize a variable called result and then we
47:30:04
iterate over every single nums that are currently present inside the nums array and we simply do x or operation with the
47:30:10
existing result value. So basically all the elements that are duplicates or multiple copies of each other would
47:30:16
cancel each other out and only the single number would have left inside our result variable. So which we can return
47:30:23
uh as the answer. So let's try to run this code.
47:30:29
Okay, seems like our solution is working as expected. Let's submit this code
47:30:36
and our code beats 99.9 83%. So pretty much all the other solutions out there
47:30:41
which is exceptionally fast and is also really good in terms of time space complexity as well. And once again the
47:30:47
coding solution is present on our GitHub repository. So this is the GitHub
47:30:53
repository that I'm talking about. Now you can notice that on this repository I have solved hundreds of lead code
47:30:59
problem. These are the most like most popular and most important lead code problems of all time. You would be able
47:31:05
to find solutions for each one of them. So all you can do is just simply search for it and you should be able to find
47:31:11
it. Now these problems are pretty straightforward and uh if you want to
47:31:16
see that how popular any particular question is I have created this Google sheet where in the Google sheet I have
47:31:23
created two sheets. First one is something I c created by myself. I went over lead code premium and went that how
47:31:29
popular, how liked and how important a question was based on how many times it was asked at different companies and
47:31:35
then I uh basically sorted them through different topics and different difficulty level which are colorcoded.
47:31:42
Then we have another list for need code 150 which is also pretty popular list out there and uh um I have been solving
47:31:49
all of these problems as well. So if you are in the process of preparing for yourself for technical interviews, yeah
47:31:55
these two can be a good resources at your disposal and uh I hope you find it useful. Links for both of them are
47:32:02
presented at uh the description of this video.
47:32:16
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we
47:32:22
are going to work upon a lead code easy problem. Uh number of ones one bits and
47:32:27
this is a bit manipulation problem. I know a lot of people don't like it but
47:32:32
uh it's really simple to understand. So the problem statement is pretty simple.
47:32:37
We just need to check that in any given integer if we represent it in binary form how many times the one value is
47:32:45
being repeated. So in this given example we are given a number like this
47:32:52
uh n is equal to uh 1 0 1 1 which is
47:32:59
which is the binary representation of the decimal value 11 that uh we need to
47:33:06
check that how many times this uh one this one is repeated in the given
47:33:11
integer and clearly over here we can see that the one is being repeated repeated
47:33:16
three times and which is the answer of this problem. And notice that the number is represented quite long because it is
47:33:23
showing that all the 32 bits of any integer and all the integer all the
47:33:29
input types would be of 32bit uh and we need to find that how many times one exist.
47:33:36
So the first approach we are going to take is quite simple and we are going to use a binary operator and.
47:33:44
Now let me show the table for and binary operator
47:33:49
for any given two values. The we can have four possible
47:33:55
combinations and a and b means if the value of a and
47:34:03
b both are one in only that scenario we are going to consider the value of a and
47:34:10
b as one. Otherwise, if there exist any single zero or both values are zero, we
47:34:15
would just simply put the values as zero. Using this logic, we can solve this problem really fast. And uh the
47:34:22
most basic approach is we would simply run a loop 32 times. And
47:34:28
every single time we are going to compare each element with one and see
47:34:34
that if we end the value that exist at any given location with our value one.
47:34:40
And if the answer is one uh uh we do uh counter plus and uh and after running
47:34:47
the loop for 32 all the 32 bits we would just simply return the value of our counter. Let me show you an by an
47:34:53
example what I'm trying to say. Suppose the input we have is 13.
47:35:01
If we represent it in binary, it would look like
47:35:07
and we would have 28 zeros and the prefix. Now we will create a value just
47:35:14
any random variable uh and we would uh
47:35:19
give it as value number one. And we will run a loop uh from 0 to 32.
47:35:29
And at inside the loop for every single value we would compare that whether this
47:35:35
one we would compare it with the rightmost element in our given input
47:35:41
array and we would do an end operation between these two values. And we would
47:35:46
we would have a counter that we initially set it up as zero. And
47:35:52
whenever we find that the answer of these two end variables is actually one
47:35:58
we would simply increase the counter. So for the first so for the rightmost position we would increase the value of
47:36:05
our counter. So counter would become one. And after we are done with this condition we would
47:36:12
simply do a left shift for this random operator in the for the given input. So
47:36:20
now one would be shifted one position to the
47:36:25
left and we would again do the same operation. So this time we will do an end operation between this zero and one
47:36:32
and the value of end operation would be zero. So we won't update the counter and
47:36:37
again we would do a left shift for this one element
47:36:43
and again we would do an end operation. the value we would get is one which
47:36:49
means we need to update our counter. So counter becomes two and again we
47:36:54
would shift our element. We do an end operation again. Again the
47:37:01
value still remains uh one. So we update our counter again and we update the counter to three. And then we would
47:37:09
subsequently update the value of uh this random character to one bit to the left.
47:37:15
And now notice that all the remaining bits are zero. So the uh end operation
47:37:21
will always uh equal to zero. So we won't update the count. And at the end of the loop we can simply return
47:37:28
whatever value of count we found as our answer. Now this approach works perfectly fine. And uh this approach
47:37:36
actually runs in big Oo of one time uh because we only have to run the loop 32
47:37:44
times which is a minimal amount of work that we have to do and the answer would
47:37:50
always be constant. So this is in itself pretty neat solution. But let's see if
47:37:56
we can go one step further and we can reduce this uh loop counter time to less
47:38:02
than 32. In order for us to understand the optimal solution, let's first take an example. So uh say we are given a
47:38:11
value n equals to 36. Now let's represent this value in binary
47:38:22
because we know that binary works like
47:38:27
2 to the^ 5 and if we do the summation of these values in decimal terms uh this
47:38:34
would become 4 and this would become 32. So 32 + 4 becomes 36.
47:38:45
Now the intuition behind this solution is that if we take one value lesser than
47:38:51
36 uh let's say 35 and if we represent this value in binary terms the binary
47:38:57
representation looks like
47:39:03
and notice that the first one that we encountered on our original input the
47:39:11
one value lesser than that has the exact opposite in terms of number of ones up
47:39:18
until this point that if we do a end operation between these two values the
47:39:26
value we would get is like this.
47:39:33
So notice that this one has already disappeared in the end result of these
47:39:40
two values. And if we repeat the same process. So now this value that we got
47:39:47
in binary the value is actually 32. And again if we repeat this same operation
47:39:54
that we do an end between the number of number by itself with one value lesser
47:39:59
than that we would gain a result like.
47:40:05
So first let's uh let's represent the value number 31 in binary.
47:40:15
And now if we do an end operation between these two values the answer we
47:40:20
would get is all zeros. Which exactly means that we would only run the loop
47:40:27
the number of times one we have in our original given input
47:40:34
because over here we only had two one in the input. So during the first iteration
47:40:40
of our loop we got rid of this first one and we can see it over here. And during
47:40:46
the second end operation we got rid of the second one as well and we got the
47:40:51
answer as all zeros. So at the beginning if we create a variable count and we
47:40:58
originally set it up to zero and every time in the given loop if we just go
47:41:04
through the loop and the value of the current valu value of current n is not
47:41:11
equal to zero we just simply increase the value of count to one. So which
47:41:18
means that during this first iteration the value of count would be
47:41:24
1 and during the second iteration the value of count would be two and after
47:41:30
that we found that the value of n is actually equal to zero. So we can simply
47:41:36
break out of the loop and when we break out of the loop we would return whatever the value of count we had found and in
47:41:43
this case the value of count we found is actually two and this solution would
47:41:48
work perfectly fine and this would be our optimal solution. The time complexity for this solution is also big
47:41:55
O of 1 which is a constant time. But the thing is the number of loop iterations
47:42:01
that we have to go through would only be equivalent to whatever the value of one
47:42:06
we are given in the original input array and we don't have to run the loop uh 32
47:42:12
times like the previous solution. So we are actually in our constant time solution we are also saving lot of time
47:42:18
and this would be the fastest solution we can reach into. Um and in terms of space complexity we are not using any
47:42:26
additional space. So space uh complexity would also be constant time and and now
47:42:32
let's move on to coding. Thank you. So first of all we will create a variable for count
47:42:40
and set it up to zero. Now we simply run a loop.
47:42:47
We will run this loop till the number is not equal to zero. And with every
47:42:53
iteration we will increase the value of count.
47:42:58
And we will simply do uh n = n
47:43:05
and n minus one.
47:43:14
At the end of the loop, we just return count.
47:43:33
Looks like our solution is working. Let's try to submit the code.
47:43:39
And yeah, submission works as expected. It's pretty efficient and neat. And uh let me know what do you think about this
47:43:46
video. And uh if you have any more suggestions, feel free to reach out to me in the comments and uh I can address
47:43:53
them. Thank you. Bye-bye.
47:43:59
Hello friends, we are still not employed by a fang company. So let's not stop late coding till we get there. Today we
47:44:04
are going to do a lead code easy problem uh reverse bits and uh this has something to do with bit manipulation.
47:44:10
So let's understand the problem statement. Basically we are given a 32-bit unsigned integer and we need to
47:44:16
reverse all the bits in it. Uh let's consider it by an example. Suppose the
47:44:22
value we are given n is equal to 5 and if we represent it in binary the binary
47:44:27
representation would be and since the given input is 32bit uh
47:44:36
all the other bits would be zero. Now we just need to return a new element uh
47:44:42
reverse that looks like the exact reversal of this binary value. So
47:44:50
this the so the rightmost bit on the original
47:44:57
input would be the leftmost bit on our new uh variable. So the value should
47:45:03
look like 1 0 1 and all the remaining zeros uh
47:45:10
because it this one is also 32 bit. So basically the rightmost zero would be at
47:45:16
leftmost position in our new variable and we need to return this. The problem statement is really easy to understand
47:45:22
and let's see that what could be the approaches we can take to solve this.
47:45:30
In order to solve this problem, we are going to use bit manipulation and specifically we are going to use uh two
47:45:36
bit manipulation operators. Uh first one is and operator and second one is or
47:45:43
operator. And let me show you by truth table what each uh of these rep uh
47:45:48
operations represent and these are the symbols to represent them.
47:45:56
So the possible value for a and b we could have is
47:46:04
so for a and b if all both the values are one then only we consider a and b as one otherwise if there exist a single
47:46:11
zero we will uh keep their value as zero. So this would be the table for a
47:46:16
and b and in a or b if there exist a single one we would consider the value
47:46:23
for a or b to be one. So if both are zero then only we would have a or b as
47:46:29
zero otherwise the value would always be one. Now let me show you that how can using these two operators we can uh
47:46:36
calculate our solution. We are only given one thing over here. Uh the input parameter n and suppose our n is five.
47:46:44
So the values would be like this. The new variable that we are
47:46:52
trying to determine reverse is actually unknown to us and that will have all the
47:46:58
values that are in reverse order for the given n
47:47:04
and we know one thing that all the values in given n is actually 32
47:47:11
bits not more than that. So the first intuition is that if we run a loop uh 32
47:47:18
times and every single time we take whatever element is present in n and if
47:47:23
we put it in our reverse uh variable. So whatever element we have present in our
47:47:30
n we put it in the reverse variable and then we start shifting the reverse variable one step to the left side. So
47:47:37
at the end of the loop our reverse variable would be exact reverse of whatever value that is present in the
47:47:44
given n. So let's determine that what would be our algorithm. Initial value
47:47:50
for our reverse parameter would be zero. So the entire value would be and when I
47:47:56
say zero I mean that all the 32 bits would be zero for the reverse element.
47:48:04
Now at the beginning of and we would run a loop from i =0 to i = to 32 and at the
47:48:13
beginning of our loop we would have a condition that every time we are going to left shift the value of reverse
47:48:20
parameter uh to one bit. So at the end we would have rotated any value that is
47:48:26
present over here we would have rotated it to 32 times and it would end up on
47:48:31
the leftmost position. But after the rotation of the value. So
47:48:38
first of all, so inside the loop first of all we will
47:48:43
rotate one bit to the left
47:48:48
and we would represent it with this uh symbol. Next what we are going to do is
47:48:54
somehow we would have to get whatever value of n is present. we need to copy
47:49:00
that value for that particular element and put it somehow put it on the
47:49:05
subsequent position at our uh reverse order. So how can we do it and we know
47:49:14
based on our uh and and or operators. So at any given moment the possible value
47:49:20
for n would be either zero or one and we want to copy whatever value of n exist
47:49:27
in our reverse uh parameter a reverse variable. So if we do an n and one
47:49:37
operation then this would specify and this would provide us with whatever
47:49:43
value of n there exist. So suppose if the value of n exist as zero and if we
47:49:48
do an and operation with 0 and one the result we would get is zero. If the u if
47:49:55
the value of n exist as one and if we do an operation 1 and 1 the value we would
47:50:01
get is one. So this is how we can get the exact value of one that is present.
47:50:07
Um exact value of n that is present. And once we calculate this value that n
47:50:14
and one we need to put this value in our reverse
47:50:20
variable. But the thing is in our reverse variable all the values are initially seted up to zero. So all the
47:50:28
values are zero and the the potential value of n and one operation could be
47:50:33
either zero or it could be one and whatever we get over here we need to
47:50:39
transfer it to our reverse variable and the way we can do it is if we simply
47:50:45
do whatever element is present at our reverse variable at our reverse variable
47:50:51
and if we do an or operation with uh whatever the answer we get from n and
47:50:58
one we would be able to put the exact value that was present at n at given at
47:51:05
any given moment. So the operation that we are going to do is current value of reverse we have with and we will be
47:51:14
ordering that with n and one and suppose initially so if the value of n is equal
47:51:22
to zero the answer after this operation would become zero and we know that the
47:51:28
value of reverse is initially set to zero. So we would be doing zero or zero
47:51:34
and the answer we would get a zero and we would shift it to our reverse and
47:51:40
at every single iteration we are going to do a left shift on the reverse
47:51:47
parameter. So whatever value we we set up at the first at the end of the 32
47:51:52
iterations it would end up over here. And
47:51:58
so we are taking care of the value of reverse parameter by shifting them one parameter left. But we also need to
47:52:05
shift the values of a given n one parameter one step one bit to the right
47:52:10
side. Uh because we need to calculate every single value of n. So suppose the
47:52:17
value of n is like 0 1 and then bunch of zeros and then uh one and this comes out
47:52:24
to be the whole 32 32 bits. We need to calculate every single value of n that
47:52:30
is present and we need to put it in the reverse order. So at the beginning of our loop we will calculate this value.
47:52:36
We would put it in our reverse uh loop. Uh and once that is done uh this value
47:52:44
would be stored over here initially in our reverse variable but we know that we are doing a left shift operation on our
47:52:50
reverse variable. So eventually the value will keep on transporting on the
47:52:56
left side and it would end up at the first position which is what we want. But the thing is on the n on the given
47:53:04
input we need to do a right shift operation. So we keep on eliminating the
47:53:10
values that we have already calculated and we are uh eventually uh when we come
47:53:15
to the end of the 32nd bit we would come to this value. So 31st bit would become
47:53:21
this value and this value would be entered at the second position reverse variable.
47:53:28
So I hope this makes things uh clear. I know it's a little bit uh tricky to
47:53:34
understand but once you will do an example by yourself uh with this uh expression that reverse the value of
47:53:41
reverse is actually the reverse we currently have or n and one and after
47:53:49
this we would be able to copy whatever value of n we have to our reverse for that particular bit and then it's just a
47:53:56
matter of uh shifting the values of reverse on the left side and shifting the value of n on the right side and at
47:54:04
the end of the loop we can simply return the value of reverse variable and this would be our answer. So now let's
47:54:12
calculate the time complexity for this approach. Basically the time complexity would be
47:54:19
big O of one because the only work we need to do is we need to run a for loop
47:54:26
uh for 32 times and that can be done in constant time and even for the space
47:54:32
complexity we we can complete the complete the entire iteration in just constant time because we are not using
47:54:38
any additional data we are just using couple of parameters to store some values and uh this would be a very fast
47:54:45
solution. And it's really simple to understand. But the thing is we need to come up with uh little bit of logic and we need to
47:54:52
have little bit of understanding of uh the bit manipulation operators. And now
47:54:57
let's move on to coding. So first of all we will create a
47:55:03
variable reverse and initialize it to zero.
47:55:11
Now we will run a for loop.
47:55:17
Inside the for loop, we will first of all do a left shift on reverse.
47:55:24
Then we will apply our logic to calculate the value of n to reverse.
47:55:32
So we will do reverse or with n and one.
47:55:43
And now what we just do a right shift one bit for the variable n.
47:55:53
And at the end of and after the loop we simply return the value of reverse.
47:56:01
Let's try to run this code. Yeah, looks like our solution is working. Let's try to submit it. And yeah, our submission
47:56:09
worksh faster than all the other submissions. But uh this is not true. This is because
47:56:14
the uh solution runs in the constant time. And uh hope you like the video. Let me know what kind of videos you want
47:56:21
me to do next. And uh if you have any suggestions regarding my videos, feel free to let me know so I can improve
47:56:26
upon them. Our aim is to clear the fang. And uh we are not going to stop till we
47:56:31
clear fang interviews. Thank you. Bye.
47:56:40
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we
47:56:46
are going to work upon a lead code easy problem missing number. And uh let's understand the problem statement.
47:56:52
Basically we are given an array of numbers uh containing n distinct numbers in the range of uh 0 to n and we need to
47:57:01
return that there is one number that is missing and we need to return the missing number. So if we take the first
47:57:07
example the range we are given is 0 1 2 and 3.
47:57:18
But we when we see the actual input of uh nums
47:57:23
the in the input we only have three 0 and 1 that if we start cancelelling out
47:57:30
the numbers that are present in nums and uh also present in our given range
47:57:40
zero can be canceled out. one can be canceled out and three also can be canceled out but uh the value number two
47:57:49
is present in our range but not in the given input. So we would simply return
47:57:54
the value uh two as not being present and uh two is two being the missing
47:58:01
number. So there can there can be multiple approaches on how we can solve this uh problem.
47:58:10
Okay. And uh we would try to uh keep in mind with this follow-up as well and we will try to solve this problem in big go
47:58:17
of one space complexity and big go of n runtime complexity. So the f first two
47:58:22
trivial approaches we have in our mind is uh first one that if we sort the input array
47:58:29
we can uh clearly we can solve this problem easily. But the issue with the sorting approach approach would be that
47:58:36
the runtime complexity would be uh n login
47:58:44
because we need to do uh sorting first and that takes n login time. Uh second
47:58:49
approach is to use a hash set and we would keep on storing all the
47:58:54
values of uh nums input in the hash set and uh then we would iterate with the
47:58:59
range loop and uh go over hashet to see if the value exists in the hash set or not or not and eventually we would find
47:59:06
a value that exists in range but does not exist in hashet and uh that would be our solution and the good thing about
47:59:13
hashet approach is that runtime complexity would be big of n and but the issue comes for the space complexity uh
47:59:20
and the space complexity for this approach would also be big of n
47:59:25
which is not what we want. So let's see what would be the optimal solution and I would be showing two optimal solutions
47:59:31
in this coding problem.
47:59:36
So our first optimal approach is actually pretty simple. Basically we are given two two items. Uh first one is
47:59:43
range that is from zero all the way up to n
47:59:48
and second one is nums input array where the values are zero all the way up to n
47:59:55
but one of the value is missing and we need to find this missing value. So the
48:00:01
most simple approach to do is we run a loop we run a for loop on this range
48:00:07
parameter and for every single value in the given input uh from zero all the way
48:00:13
up to n we simply do an addition of all the values we store the result of all
48:00:19
the elements in the range in a parameter called range sum
48:00:27
and we would find some value over here and again we repeat the same process but this time for nums. So we do the sum of
48:00:36
all the elements in the num uh with another for loop. We store the result of
48:00:41
a sum in a new parameter called num sum. You can put any name. This is just
48:00:48
randomly something for taking the name. And then when we do a difference between
48:00:54
range sum and this num uh uh number sum the difference would actually be the
48:01:00
missing number and this uh this way we would be able to
48:01:08
find the solution pretty quickly. Let's take it by by a quick example.
48:01:15
So clearly we can see that this um value one is missing. So the sum of all the
48:01:20
elements over here would be 10 and the sum of all the elements over here would
48:01:25
be 9. So if we simply do 10 - 9, we
48:01:31
would find the value 1 which is the missing number. And this solution is
48:01:36
pretty simple to do and uh the time complexity would be big of n because we
48:01:43
are just uh simply running two for loops separately. So we are not doing much
48:01:48
work in terms of time complexity and for the space complexity other than storing
48:01:55
the value for just couple of parameters uh we are not consuming any additional
48:02:00
space. So the space complexity would be constant and this is uh an optimal
48:02:07
approach that we are asked as a follow-up in our original input.
48:02:16
For the second optimal solution, we are going to use a bit manipulation
48:02:22
and specifically uh we are going to use x or operator. So if you don't know what
48:02:28
x or operator is, let me give you a quick tutorial on what each value is being represented when it gets x odd
48:02:36
with uh some other value. We can only have four possible values
48:02:43
for a and b because all the values in computer system are represented as binaries.
48:02:50
Now in the x or if both values are zero we consider the value as zero. If any
48:02:56
one value is one we consider the x a x or b as one. Uh same goes for this one
48:03:01
and if both values are one we again consider a x or b as zero. Now let's see
48:03:07
that using this logic how can we u find the missing number.
48:03:13
So now consider this property that for any given value n if we x or n with
48:03:20
itself the answer we would get is actually zero and let me show you what I
48:03:26
mean by that suppose our current n is actually six and now let's represent this in binary
48:03:36
and now let's try to do n x or n and
48:03:42
this is the symbol for X or in uh computer um in programming language.
48:03:48
So if we do the result uh 0 0 is 0 1 1 is 0 and 1 1 is again 0.
48:03:59
So if we exor two values together the answer we get is actually zero. But if
48:04:06
we x or so suppose if we x or the values
48:04:11
like 6 x or 6 x or 3 the answer we would
48:04:17
get is actually the value by itself. Uh so because
48:04:23
6 x or 6 would be zero and now let's try to x or 3 with this given zero. So the
48:04:32
binary representation for three is equal to 011. And now when we try to exor these
48:04:40
two values uh 0 and three
48:04:45
the answer we would get is 0 1 1 which again means three. The number that we
48:04:54
exort zero with. And we also notice one more additional
48:04:59
property over here that whenever we x or two values. So 6 x or 6 x or 3 gives the
48:05:07
result as three. Also if we change the order and if we put any order like 3 x
48:05:13
or 6 x or 6 this will also result in three. And if we do like 6 x or 3 x or
48:05:21
6, this will also result in the value three because order doesn't matter. Uh
48:05:27
if we are exoring two values by itself, uh both are going to eliminate
48:05:32
themselves and their answer would be zero. So whatever is remaining would be uh the answer of this one. And we can
48:05:40
repeat this for whatever number of times you want. So we can if we do something like uh 2 x or 3 x or 2 x or 6 x or 6 x
48:05:52
or 7 x or 7. If we run this entire thing
48:05:57
still the answer after this would be three because notice that over here two cancels itself six cancels itself and
48:06:05
seven cancels itself and only three is going to be remained. So now we now
48:06:10
since we have established all of this let's try to see that how can we how can this be useful for us in this given
48:06:16
problem. The input for our given problem is
48:06:22
actually we are given range and we are given the input number. So
48:06:30
suppose for an uh suppose for an example the range we have is uh 0 to 4. So 0 1 2
48:06:37
3 let's consider 0 to 3. And the input parameters we have is suppose 1 3 and 0.
48:06:47
So notice that number two is missing. Now if we were to use this x or logic
48:06:55
that if we exor all the values in the range with all the values in the nums we
48:07:02
would get something like this. 0 X or
48:07:07
1, X or 2, X or 3 for this range
48:07:12
portion. And if we X or this with the nums input, we will get 1 X or 3 X or 0.
48:07:23
And if we combine both of these, basically all the values that are same
48:07:28
would be eliminated and would be turned to zero. So this zero would cancel out this zero. This one would cancel out
48:07:35
this one. And this three would cancel out this three. And notice that right over here we just determined that the
48:07:42
order in which XR happens does not matter.
48:07:48
Everything is uh not right next to each other. still they will cancel out each
48:07:53
other and at the end we are only going to be remained with the value that is
48:08:01
not at all present in this nums input. So in the nums input we don't have the
48:08:07
value number two present. So the result of range
48:08:14
x or nums would actually give us the value two and
48:08:20
uh the result two we can simply return it and this would be our solution. So
48:08:27
this is a very neat very unique solution and because we have the knowledge of x or we are able to come up to this result
48:08:35
and if we use this in an any if you use this in any interview this clearly shows that you have very sound uh knowledge of
48:08:42
computer concepts and you know how to apply them when they seem fit. Uh this
48:08:49
would definitely give you a very extra very sharp edge over all the other candidates. And uh let's do the uh
48:08:58
complexity analysis. So for the time complexity we are actually doing everything in just uh the single loop
48:09:06
for one loop for range and one loop for nums. Uh so the time complexity would actually be big of n and the space
48:09:14
complexity would actually be big of one because we are not using any additional
48:09:19
space. So this would be the most optimal solution and this is what the problem is
48:09:26
asking us to find. Now I'm I showed two optimal solutions but first optimal
48:09:31
solution is very trivial to understand. So I'm not going to code it up and I'm only going to code up this X or
48:09:38
solution.
48:09:45
So we will first of all create a variable xr and we initialize it to zero.
48:09:54
You can give any name. And now we will run a for loop starting uh from the range. So int i =0
48:10:04
to i is less than or equal to ns.length length
48:10:11
i ++ and every time we will exort the number
48:10:17
with itself. So
48:10:22
now again we will run another loop and this time we will run it for the given input array.
48:10:33
Notice that we are only using i is less than number of length and over here we are using uh less than or equal to
48:10:40
because in the range we have one value more than whatever the value whatever the length of uh number is.
48:10:48
And again we repeat the same operation x
48:10:54
with the value in the given input array.
48:11:01
And now we will simply return whatever we found in x or that this would be our
48:11:07
missing value. Let's try to run this code. Looks like our code is running. Let's
48:11:12
try to submit this uh submit it. And yeah, our solution works perfectly fine. It's actually pretty fast and pretty
48:11:18
efficient. And uh hope you like this video. I'll be posting the solution in
48:11:24
the comments. And uh let me know if you have any suggestions for the videos. Uh
48:11:29
yeah, let's clear fang together.
48:11:36
Hello friends, we are still not employed by a fang company. So let's not solve lead coding till we get there. Today we
48:11:41
are going to work upon a lead code medium problem sum of two inteious. So let's understand the problem statement.
48:11:47
Basically we are given uh two elements uh a and b and we need to return the sum
48:11:53
of two inteious without using the plus or minus operator. And uh the problem
48:11:58
statement is really simple. Basically we are given two values a and b and uh we
48:12:04
need to return the sum of a + b equals to in this case three but without using
48:12:11
the plus operator. So let's see how can we do that. We are
48:12:16
going to use two bit manipulation operators. Uh first one is something called x or or exclusive or and second
48:12:24
one is and. So let me uh show you what each of them does and what does it mean.
48:12:31
So we are we will consider a table like this
48:12:37
where we are given the values of a and b and the value of a x or b.
48:12:46
Now these are binary elements. So we can the only possible values we can have for
48:12:51
a and b is 0 and 1. And we can have four possibilities. Either both are 0 0 0 1 1
48:13:01
0 or 1 1. And the answer for a x or b would be 0 0 is
48:13:09
0. 0 1 would become 1. 1 0 would also become 1. And if both are one, we would
48:13:15
again consider it as zero. So this is just something that we keep in our mind and we will use it further down in our
48:13:22
equation. Now let's see what would be the table for a and b.
48:13:31
Now as the name suggests a and b we only set the value as one if both entries are
48:13:38
one. Otherwise uh if there is any single zero present we we get the answer of a
48:13:45
and b as zero. And now let's see how can we use these two operators to find the sum of any two
48:13:52
values for our given problem. So suppose we are given two values like this a = 5
48:14:01
and b = 3. So the sum of a + b as we
48:14:07
know is 8. And let's see how these values are represented in uh binary. So
48:14:15
a would be represented as 1 0 1 and b would be represented as 0 1 1 because in
48:14:23
binary operator the value of any element is actually done as 2 of 0 2 of 1 2 of
48:14:31
two. So uh this becomes four and this becomes 1. So 4 + 1 = to 5. And uh same
48:14:39
over here this is 2 and this is 1. So 2 + 1 equals to 3.
48:14:46
Okay. Now let's try to do a summation of these two values. So 1 + 1 we cannot do
48:14:52
two over here because this is a binary representation. So we will uh do as zero
48:14:58
and we would have one as carry uh that we carry on towards the left value and
48:15:03
again we get 1 + 1. So again the value becomes zero and we have a carry that we
48:15:09
need to consider on the left side. If we take the carry again we get the value zero and we will have a carry over here
48:15:16
and we don't have any value over here. So we can just consider uh this as 0 0.
48:15:21
So with the carry the value becomes one. And if we do the uh if we find the
48:15:27
binary value for this one, this is actually two of 0, two of 1, two of 2 of
48:15:34
the power three. So the value 2 of the power three is actually 8 and which is
48:15:41
our answer. So if we do the simple addition of binary values, we can also
48:15:47
get the answer answer as eight. But the problem over here is that we should not
48:15:53
be using the plus operator. So we cannot just simply add these two values. So the
48:15:59
longer route we can take is we can try to do a x or b first and then we would
48:16:09
do a and b and we would move the values to one point left. This is simply what
48:16:16
we are going to do for the given elements until the point where we find
48:16:21
that the values of a and b uh as zero.
48:16:26
So this is the broader idea of our algorithm. And let's see what I mean by that.
48:16:35
So the value of current A is 1 0 1 and B
48:16:41
is uh 0 1 1. So let's try to do a
48:16:49
X or B. This is the symbol for X or in
48:16:54
uh computer language. So we will simply use this one. And let's see what the
48:16:59
value becomes. So we know that 1 1 is 0 1 is 1 and 1 0 is also 1. Now we need to
48:17:10
do the operation of a and b. We are
48:17:15
doing this operation to find the carry value with a and b values. And uh
48:17:20
because we are finding the carry values, we know that whenever we have a carry at
48:17:26
any location, we need to move it one step on the left side. So we will again
48:17:32
use the same logic that we will use a and b to find the carry value and we
48:17:37
would move it one step on the left side. So let's see what the values would be
48:17:42
for a and b. So basically we have one one over here.
48:17:48
So that value would become one. And notice that we are writing one over here
48:17:54
and not over here because we are shifting the element on one step towards
48:17:59
the left side. So we have 1 one as one. Next values we have is 1 0 sorry 0 1 and
48:18:08
we set it up as 0 and again we have 1 0. So again we set it up as zero and
48:18:14
because we don't have any value over here we shifted one value on the left. We can consider the value as zero over
48:18:22
here. Now we have calculated the results for a x or b and
48:18:30
a and b and we have moved them towards the one one step on the left. In our
48:18:36
algorithm, this would become our new A and this would become our new B. And we
48:18:42
would have a loop that until we get a value of B that is not zero, we would
48:18:49
continue with this operation. And let's see where we will get.
48:18:54
So now the values for a and b would be
48:19:00
a would become 1 1 0 and b would become
48:19:05
0 0 1 0. And now let's let's repeat the
48:19:11
operations again. So first we will do a
48:19:16
x or b which gives us 0
48:19:23
1 1 becomes zero and we will have a carry but we will consider it later 1 0
48:19:28
becomes 1 and 0 becomes zero. Now let's do a and b and shift it to one bit on
48:19:37
the left side. And because we have to move it one bit on the left side, we will start it over here. So 0. So 0 0
48:19:47
becomes 0. 1 1 becomes 1. 1 0 becomes 0.
48:19:53
And 0 becomes 0. And because we don't have any a value on the rightmost uh
48:19:58
part, we will consider it as zero. So again, we will assign the values as a
48:20:05
and as b. And we notice that b is still not zero. So we will continue with our operations and we will continue with our
48:20:11
loop. So
48:20:17
again let's repeat the same operation. So a mod b becomes
48:20:23
0 0 again zero again zero and zero. So
48:20:29
all zeros we are getting as a x or b. And now a and b
48:20:37
shifted one element on the left side becomes we start one element on the uh one
48:20:44
element from the rightmost element. So 0
48:20:50
again 0 for these two 1 one becomes one 0 0 again becomes zero and we have one
48:20:58
blank element on the rightmost uh bit. So we can consider it as zero. This
48:21:04
becomes our new A and this becomes our new B. We notice that B is still not zero. So let's repeat the operation.
48:21:14
And now we are going to do a x or b
48:21:20
equals to 0 0 0 1 0 and a and b
48:21:31
shifted one bit on the left side. So notice that on this a value we don't
48:21:38
have any ones which means that under no circumstances we can have this a and b
48:21:46
where we get one answer because a is always zero. So
48:21:52
same thing applies over here and basically this value would become all
48:21:57
zeros 0 0 0 0. And now again we assign our values. So
48:22:05
this becomes a and this becomes b. And notice that in this scenario b is
48:22:10
completely zero. So we can break out of the loop. And when we break out of break out of the loop, we can simply return
48:22:18
the value of a. So the value of a we have found in this scenario is 0 1 0 0
48:22:26
0. And this is a binary number. If we were to convert it to decimal value, we
48:22:34
can we can understand this as uh 2 of 0, 2 of 1, 2 of 2, 2 of 3 uh 2 to 3 and 2
48:22:44
to 4. So all of these values are zero. So we don't consider them. This one is 2
48:22:50
cube which is 8. So we can return a as 8. And this would be our final answer.
48:22:58
And if we see the original two values in our request, basically we had the two
48:23:04
inteious a= to 5 and 3 and we get our answer perfectly defined over here and
48:23:12
we reach to this answer without using the plus operator. So this this would be
48:23:19
our solution. And now let's calculate the time complexity for the given problem.
48:23:25
So basically if we see the given input over here we have a constraint that all
48:23:32
the values are between negative 1,000 and positive 1,000 which means that
48:23:38
essentially we can calculate the time in a constant uh time complexity big of
48:23:44
one. We don't need to calculate any anything additionally because overall the input is quite small and we can
48:23:51
simply uh do it uh constantly and also the space complexity would be bigo of
48:23:58
one because we are not using any additional space we are just using couple of variables to store just few
48:24:04
values. Uh so this is a really ideal approach and I know that lot of people
48:24:10
uh don't like to have bit manipulation and uh they simply ignore it or they
48:24:17
hate it and most of the times companies don't tend to ask this kind of questions
48:24:23
but we are preparing for fang we are not preparing for some random uh company and
48:24:28
if you want your dream job why would you compromise so I would just suggest that go over it it might take you like 2 3
48:24:36
hours to go through all the bit manipulation questions and understand the concepts but once you are done with
48:24:42
that you will have an extra edge in the interview so I would highly recommend not to skip anything and not to put
48:24:49
anything on the chance I will and now let's move on to the coding and we are
48:24:54
going to implement the solution so if our intention is to just sub
48:25:00
submit it for the sake of submitting it and uh have it accept accepted by lead
48:25:05
code. We can simply write one line of code. We can simply return a + b and
48:25:11
apparently it works. Yeah. But this is not what we want. So
48:25:19
we would be now we would be writing the the complete solution
48:25:24
that we would use in in an actual interview. So first of all we will create a while
48:25:31
loop uh to see if the value of carry is actually zero or not
48:25:38
and we are going to store the value of carry in the B element. So well b is not
48:25:44
equal to zero. Now we will create a variable to store
48:25:50
the value of a x or b. Let's name it temp.
48:26:01
And now we will calculate carry as well.
48:26:08
We will do a and b and shift it to one place uh left shift
48:26:17
it to one bit on the left side. And now we simply store the value of temp in a.
48:26:23
So a becomes our temp and as mentioned earlier we will store
48:26:28
the carry in b and yeah that's pretty much it. Once
48:26:34
this loop runs our solution should be stored in a. So let's return a.
48:26:43
Let's try to run our code. Looks like our solution is working. Let's try submitting it.
48:26:51
And yeah, our solution works pretty neatly. It's apparently 100% faster than all other solutions, but actually this
48:26:58
is not true. All other solutions are also 100% faster because the runtime is
48:27:03
in constant time. So hope you like the video and uh let me know in the comments
48:27:09
if you want me to update anything in the video. Our aim is to clear fang interviews. I'm making these videos so I
48:27:15
can practice for myself and also I can uh spread the knowledge I have gained to
48:27:20
like other like-minded people and uh yeah see you soon.
48:27:36
So the lead code problem we are going to solve now is called reverse integer. Now this one is an extremely popular lead
48:27:42
code problem and also a medium one. Basically we are given a signed 32-bit integer x and we need to return x with
48:27:50
its digits reverse. So basically uh let's say that if the given x value is 1
48:27:55
2 3 then we need to return x is equal to 3 2 1. uh same way if we are given a
48:28:01
negative number let's say x is equal to minus 435 then once again we need to return as minus then 5 3 4 and uh so on
48:28:11
and so forth. So this is the basically the whole problem statement. Now we are also given some condition where we the
48:28:18
given number should not exceed the maximum range of a 32-bit integer. Uh if
48:28:24
that is the case then we need to return zero. So let's try to understand that what is going to be the most common
48:28:30
logic to solve this problem. Let's say that I tell you that we are given values 1 2 and 3 and I ask you to reverse it.
48:28:36
Logically as a human what you are going to do? You will first go to this number. you will find the very last number and
48:28:44
you would put that very last number into the front of this new X that we are trying to create and then eliminate this
48:28:50
number from your site and once again repeat the same process and repeat the same process for all the remaining
48:28:56
numbers. So basically three would come over here, two would come over here and one would come over here and this would
48:29:01
be our answer that we are going to return. This is exactly what we are going to do to solve this problem as
48:29:06
well. Basically all we need to do is uh just do the modulo by 10 operation for
48:29:13
this given x value and at every instance we are going to uh do the operation that
48:29:19
x is going to be x divided by 10 and we are treating x as an integer value. So this division by 10 would basically
48:29:25
yield uh that we are eliminating the very last element every given moment. So let's see that what is the solution I'm
48:29:32
proposing uh if the given x is equal to 437 suppose like this. Okay. Then first
48:29:38
of all on this given x we are going to do x modulo by 10 operation. So we are
48:29:43
dividing it by 10 and finding the remainder. So remainder in this case is going to be seven. So first of all in
48:29:50
our new x we are going to add seven as the very first value. Uh so basically
48:29:57
how we can add this value basically we will just do uh like 10 to the power uh
48:30:03
0 and 10 to the power 1 and so on and so forth. Uh this is how you add digits and
48:30:08
multiply by current value we have and add it to the existing value. So it's very common uh typically we do it with a
48:30:16
small operation that we will see in the code. So we would take this value in and we would put it over here. After that we
48:30:22
are going to run this operation x is equal to x / 10. So that would eliminate this um 7 from this existing number. So
48:30:30
after this once again we are going to repeat the same operation. Now this time the number remainder number is going to
48:30:36
be three. So once again we would append three over here and then remove three from this existing number. And lastly we
48:30:42
will have four. So we will add four over here. And once we have no characters left inside the x or the given value of
48:30:49
x is less than uh 10 basically we will just add that value and then get out of the loop. Also at the same time we will
48:30:55
have to understand that at every given instance while adding or building this number are we going out of the bounds
48:31:03
for the given integer value of the 32-bit number. So for that the only
48:31:08
thing we can do is just we can just compare whenever we build a new entry for X and if that entry exceeds the
48:31:15
existing limit for the integer or 32-bit sign number then we will just simply um
48:31:20
return zero in this case. So this is the whole solution and uh typically this solution would work in the total number
48:31:27
of given u numbers. So basically let's say that we are currently given five
48:31:32
numbers. So 1 2 3 4 5 then the time complexity is going to be big of five
48:31:38
because we will have to do it for every single character by character. So this is actually going to be big of
48:31:43
logarithmic of x value where x is going to be the the type of system that we use
48:31:49
to represent the numbers. Now since we are using 1 to 10 numbers. So this is going to be a decibel system. So simply
48:31:56
we can say that this is going to be logarithm of of x for the total number of given characters. But overall this is
48:32:01
a very simple straightforward solution. And now let's quickly see the coding solution. So first of all we are going
48:32:07
to initialize a new variable called reverse where we are going to store the answer. And then we are going to run our
48:32:12
loop that while the given x is not equal to zero. We will first extract the last digit and that is by doing the modulo
48:32:19
operation and then we would simply divide the current number of x by 10 and because it's an integer so we would just
48:32:26
remove the very last character. Now we simply need to check the overflow condition before we start updating the
48:32:32
reverse uh functionality. So we are only checking that if this given reverse value is already greater than the
48:32:38
integer by max value by 10 or if that is not the case and if the pop is greater
48:32:43
than this value then we can simply return zero. Otherwise uh we also need to check for underflow case the same
48:32:50
operation in the reverse order that if we are going out of bounds in the minimum value case. If either of this is
48:32:56
the case we can return zero. If that is not the case, we simply add that value and update the existing reverse number
48:33:03
by multiplying the current reverse number with 10 plus adding the pop value or the last value we added and we can
48:33:09
simply return the reverse value. So let's try to run the scenario. Okay, seems like our solution is working as expected. Let's submit this code
48:33:18
and our code runs beautifully beats nearly nearly 82% of all the other solutions which is pretty good. So once
48:33:25
again the coding solution is present in our GitHub repository. Feel free to go and check it out from there. Thank you.
48:33:45
Hello friends, we are still not employed by a fang company. So let's not stop lead coding till we get there. Today we are going to work upon a lead code easy
48:33:52
problem counting width which in my opinion should be a lead code medium problem. Uh let's understand the problem
48:33:58
statement. So basically we are given an uh integer n as input and we need to
48:34:05
return an array uh such that it defines that for every single value from the
48:34:11
range of uh zero all the way to whatever given n is how many times the value one
48:34:18
is repeated in its binary formation. So let's try to understand this with with an example.
48:34:25
Suppose our given input is three. So the range from 0 to n would be 0 1 2 3. And
48:34:32
if we represent these values in binary uh the representation would look like 0
48:34:38
0 1 1 0 1 1. And we need to return an answer array uh such which is of n + one
48:34:47
size uh such that it represents that for every single value from 0 to n how many
48:34:54
times this bit one is being repeated.
48:35:03
So now for the zeroth position we don't have any ones. So we enter the value zero. For the first position we have one
48:35:10
one bit so we enter as one. Uh same goes for the second value so we again add
48:35:16
one. And for the third value we have two ones. So in the answer we provide as
48:35:23
two. And this would be our array that we would return as our answer. So let's see
48:35:29
what are the different approaches we can take.
48:35:36
So the first approach we can take over here is of one of the previous lead code questions that we have already solved a
48:35:42
number of one bits and uh let me give you an overview of the solution we had achieved previously. So if we are given
48:35:50
any number n is equal to 5 and if we represent it in binary it becomes 101
48:35:55
and if we want to find that how many number of one exist in the given uh input we simp we would simply do an end
48:36:03
operation between the number and uh it's uh one value lesser than the number of
48:36:08
itself. So one value lesser over here would be four. And if we represent it in binary it becomes like this. And if we
48:36:14
do an end operation between these two values, the answer we get is uh 0 0 1.
48:36:20
And this would be our first iteration. And now we would repeat the same process. So now again the number we
48:36:26
found after doing this end is four. And we would do an end operation with one value lesser than four. So three would
48:36:34
become 0 1 1. And if we do an end operation between these two values, the
48:36:39
answer we get is 0 0 0. And the moment we get zero answer, we break out of the loop. And at the beginning of our loop,
48:36:46
we would create a value a variable count. And only initially it would be
48:36:52
set up to zero. And with every iteration, we would increase the value of count. So during this iteration the
48:36:59
value of count would become one and during this iteration the value of count would become two. And at the end when we
48:37:06
find that the number is actually zero we would return whatever value of count we
48:37:11
found as the number of ones that exist in our given input. So we found that in
48:37:18
our given input five it has two number of ones. We can repeat the same formula
48:37:24
for the given input. And uh let me show you how we can do it. Suppose the input we are given n is equal to 4. we need to
48:37:32
create an array from 0 to four and we need to calculate that uh for every single value how many number of ones are
48:37:40
present in that given input. So the array the answer array would be
48:37:49
we would need to provide that how many number of ones exist. So we can create a function called count one
48:37:57
and for and we can run a loop over the all these values and every single time
48:38:04
we would pass on whatever the current value we are trying to find the count for and when whenever we run this uh we
48:38:13
run this function that uses this logic uh the one that we just uh discussed
48:38:20
then we would be able to find that how many numbers number of one exist for every single given element and when we
48:38:26
get the answer back we can just simply fill in our array and return this as answer. This solution would work
48:38:33
perfectly fine and the time complexity for this solution would be u n because
48:38:38
we will have to run a loop towards the entire towards all the all all the given values and we for every single value we
48:38:46
would have to run this operation count the number of ones and this loop runs
48:38:52
for the time being of number of ones that exist in any given uh input. So
48:38:58
over here for number five there exist two uh two ones. So we would have to run
48:39:04
the loop twice. Uh suppose if we are given any uh n is equal to like this
48:39:10
then the loop will run six times. So we can say that this uh solution
48:39:17
basically works uh in the time complexity of big O of n * log n
48:39:25
because in order to find this count because in order to find number of ones
48:39:30
we would have to run multiple loop we will have to run multiple iterations in this count one uh solution. So this is
48:39:39
in itself a pretty efficient solution but we need to see that if we can find a better approach and can we have an
48:39:45
optimal solution we can have optimal solution. Let me show you how we can achieve that.
48:39:55
Now in order to find the optimal solution first let's try to understand that how the logic actually works. If we
48:40:02
want to find the number of ones in any given element. So the operation we are
48:40:08
doing is basically we take n and n minus one and then we do a counter ++ we can
48:40:15
represent it in a different manner. So let first let's try to understand that suppose n is equal to 9. The actual
48:40:22
calculation we are doing is n minus one we are doing an end. So
48:40:28
basically this means that after the end operation
48:40:35
we get the value as and the value this comes up as uh 8 and
48:40:43
we do an + one. So keeping this in mind and again if we do
48:40:49
it for the value number eight what we are actually going to do is uh we we are going now our n is 8 so we will do n
48:40:57
minus one as 7 and the answer is zero. So basically our n
48:41:06
is zero at this moment and we again do + one in our counter. So if we write this
48:41:14
in other way we can write it as that answer for the number nine is actually
48:41:20
whatever the answer we found for 9 and 8 + 1. And if we go down one step
48:41:31
further, the answer for actually this uh 9 and 8 is actually the answer for
48:41:38
whatever the value of 8 we found + one. We can write this exact same
48:41:46
formation as this. And if we try to calculate the value for this a uh a of 8
48:41:53
actually we can write it as a of 8 and 7
48:42:00
+ 1 for this uh particular value. And this actually becomes a of 0 + 1.
48:42:09
And we know that a of 0 is actually 0 + 1 is 1.
48:42:14
And this one is actually the value of a of 8. Now if we replace this a of 8 over here,
48:42:23
we can say that uh the a of 9 is actually
48:42:29
a of 9 and 8 + 1. And we know that the
48:42:35
value of a of 9 and 8 is actually a of 8 + 1. And we know that the value of a of
48:42:41
8 is actually this one. So we can say 1 + 1. And we can come to the conclusion
48:42:48
that the by the number of ones present in value number nine is actually two.
48:42:55
And which is what we are given over here and which is what we know. And basically
48:43:01
what we have done is we have taken this input for any single individual element and we
48:43:09
have actually computed the results. We have actually stored the results and based on those results we are able to
48:43:15
find the future values and basically we are applying dynamic programming.
48:43:25
We can simply calculate the solution for our entire array in just big O of N
48:43:30
time. Let's take another example to make things more clear.
48:43:38
Suppose our given input is equal to six. So if you want to find the answer for
48:43:44
six using the logic we found over here, we can consider this as
48:43:52
answer for whatever we find for 6 and 5 + 1. And the answer for 6 and 5 is
48:44:00
actually
48:44:08
this equals to 4. So we can write this as answer for whatever the value of four
48:44:14
we got + 1 because this turns out to be four. And subsequently if we calculate
48:44:21
the value for four we can break it down further as
48:44:28
so we can write this as uh answer for 4 and 3 + 1 for this
48:44:38
portion and + 1 for this one.
48:44:43
The answer for 4 and 3 is actually n is equal to z. So we get answer of 0 +
48:44:52
1 + 1. This would be our final answer for
48:44:59
our answer for value number six. So see over here that we have when we get to
48:45:05
value number six, we would have already calculated all the values from 0 to 5.
48:45:13
And we since we have the answer for from 0 to 5, we will use those answers
48:45:21
to quickly determine the answer for value number six. And
48:45:26
this logic enables us to get our solution in just single iteration. And
48:45:34
uh this would be a better time complexity than our previously suggested
48:45:40
uh algorithm. And in terms of space complexity
48:45:46
anyways we have to create an answer array in order to return it as a part of the answer because it is given as
48:45:53
requirement u for the given input that we are not causing we are not using any
48:46:00
additional space and we can just use the same uh array to represent the answer
48:46:06
and also use it as our dynamic programming solution. So space complexity would also be a big goal of
48:46:12
one and this is a really ideal approach and let's see let's move on towards the
48:46:19
coding.
48:46:24
So first of all we will create an answer array
48:46:31
and we would give it the size of n + one. And now we initialize the answer array
48:46:38
uh of zerooth value to zero.
48:46:44
And now we just need to run a for loop. We'll start the loop from i is equal to 1 because we already calculated the
48:46:51
value for zero. And we will run it while i is less than or equal to n.
48:47:00
And we just have to write one line of solution that if our answer of
48:47:05
uh current I is actually equal to answer of I and
48:47:16
I -1 and whatever the result of this is we
48:47:21
just add one to it and yeah basically after the loop we should have our answer
48:47:27
array completely filled up And we can simply return it.
48:47:33
So let's try to run our code. Oh, we forgot to initialize the value.
48:47:41
Yeah, looks like our solution is working. Let's submit this. Our submission works pretty fast compared to
48:47:48
a lot of other submissions. And uh as we can see that this is just couple of lines of code uh that is really doing
48:47:56
the trick. So though this is really simple to see but in order to come up to
48:48:02
this answer requires very strong knowledge of uh dynamic programming. Hope you like the explanation in the
48:48:08
videos. Let me know if you want me to do anything else with the videos or or
48:48:14
provide me any suggestions on how can I improve.
48:48:22
So this is my final message to all of you. Thank you so much for sticking around and staying until the very end of
48:48:29
the video. I know it's not very easy or quite straightforward. It's a boring topic and it has lot of complexities
48:48:36
associated with it. But I appreciate you on your commitment and your perseverance
48:48:43
throughout this entire course. Now this is not the end of the story. Keep doing
48:48:48
your part. Keep practicing. This will definitely change your life if you can crack some awesome interviews and find a
48:48:55
better job. And uh feel free to please support my channel as well, Destination
48:49:00
Fang. I don't know how many hours it took me to make this video. And it's been an incredible journey so far. What
48:49:08
started as a passion project for me to learn myself has evolved into something
48:49:13
beautiful and that has been helping people all across world. Now we live in very uncertain times. There are wars
48:49:20
going. There are people dying. There are uncertain governments and bunch of things that has been unprecedented
48:49:27
happening in the world. We don't know what tomorrow feels like. So I just have one urge to each one of you. If you can
48:49:34
help someone out in need, it can be your friend. It can be some person you see on
48:49:39
the street. It can be someone maybe thousands of kilometers away from you. No matter what, try to make this world a
48:49:47
better place. Let's help each other out. That is the only way we grow. So please
48:49:52
uh you do your part. I'll be doing my part and let's make this world a beautiful place. Also best of luck in
48:49:59
your journey and I hope you crack all the interviews you can and go as further
48:50:05
ahead in your career as possible. So till then take care.
No results found
TAP TO RETRY
English (auto-generated)
English (auto-generated)